挑战程序设计竞赛 2.5 它们其实都是“图”
Posted forever97‘s blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了挑战程序设计竞赛 2.5 它们其实都是“图”相关的知识,希望对你有一定的参考价值。
【Summarize】
1.注意对图是否连通的判定
2.灵活运用边权取负的技巧
AOJ 0189:Convenient Location
/* 给出一张无向图,现在求一个点,使得这个点到所有点的距离和最小 输出这个点的编号和距离和 */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=10,INF=0x3f3f3f3f; int n,d[N][N],c,x,y,m; int main(){ while(~scanf("%d",&m),m){ memset(d,INF,sizeof(d)); n=0; while(m--){ scanf("%d%d%d",&x,&y,&c); d[x][y]=d[y][x]=c; n=max(n,max(x,y)); } for(int k=0;k<=n;k++) for(int i=0;i<=n;i++) for(int j=0;j<=n;j++)d[i][j]=min(d[i][j],d[i][k]+d[k][j]); int ans=INF,pos=0; for(int i=0;i<=n;i++){ int tmp=0; for(int j=0;j<=n;j++)if(i!=j)tmp+=d[i][j]; if(tmp<ans)ans=tmp,pos=i; }printf("%d %d\n",pos,ans); }return 0; }
POJ 2139:Six Degrees of Cowvin Bacon
/* 求一头奶牛到其它奶牛的平均距离的100倍的最小值 */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=310,INF=0x3f3f3f3f; int n,d[N][N],c,x,y,m,a[N]; int main(){ while(~scanf("%d%d",&n,&m)){ memset(d,INF,sizeof(d)); while(m--){ scanf("%d",&c); for(int i=1;i<=c;i++)scanf("%d",&a[i]),a[i]--; for(int i=1;i<=c;i++)for(int j=1;j<i;j++)d[a[i]][a[j]]=d[a[j]][a[i]]=1; } for(int k=0;k<n;k++) for(int i=0;i<n;i++) for(int j=0;j<n;j++)d[i][j]=min(d[i][j],d[i][k]+d[k][j]); int ans=INF; for(int i=0;i<n;i++){ int tmp=0; for(int j=0;j<n;j++)if(i!=j)tmp+=d[i][j]; if(tmp<ans)ans=tmp; }printf("%d\n",100*ans/(n-1)); }return 0; }
POJ 3268:Silver Cow Party
/* 在有向图中求每个点到终点后返回的最短路的最大值 以终点为源点做一次正向路径的spfa和一次反向路径的spfa, 相加即为每个点的答案 */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N=200010,inf=~0U>>2,M=200000; int T,tim[N],q[N],size,h,t,n,m,x,ed[2],dis[2][N],in[N],nxt[2][N],w[2][N],v[2][N],g[2][N],u,e,cost; void add(int u,int x,int y,int z){v[u][++ed[u]]=y;w[u][ed[u]]=z;nxt[u][ed[u]]=g[u][x];g[u][x]=ed[u];} int spfa(int u,int S){ for(int i=1;i<=n;i++)dis[u][i]=inf,in[i]=0,tim[i]=0; tim[S]=1,dis[u][S]=0,in[S]=1; int i,x,size; q[h=t=size=1]=S; while(size){ for(i=g[u][x=q[h]],h=(h+1)%M,size--;i;i=nxt[u][i])if(dis[u][x]+w[u][i]<dis[u][v[u][i]]){ dis[u][v[u][i]]=dis[u][x]+w[u][i]; if(!in[v[u][i]]){ tim[v[u][i]]++,t=(t+1)%M,size++,in[q[t]=v[u][i]]=1; if(tim[v[u][i]]>n)return -1; } }in[x]=0; } } int main(){ scanf("%d%d%d",&n,&m,&x); for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&e,&cost); add(0,u,e,cost); add(1,e,u,cost); }spfa(1,x);spfa(0,x); int ans=0; for(int i=1;i<=n;i++)ans=max(dis[0][i]+dis[1][i],ans); return printf("%d\n",ans),0; }
POJ 3259:Wormholes
/* 给出一张n个点m条边的无向图,有w个虫洞,可以在穿越的过程中减少时间 问有没有可能回到过去 回到过去即存在负权回路,SPFA求解即可 需要注意的是不是连通图,因此在做spfa的时候要将所有的点先入队一次 */ #include <cstdio> #include <cstring> using namespace std; const int N=200010,inf=~0U>>2,M=200000; int x,S,T,time[N],q[N],size,h,t,n,m,W,ed,dis[N],in[N],nxt[N],w[N],v[N],g[N],u,e,cost; void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;} int spfa(int S){ for(int i=1;i<=n;i++)dis[i]=inf,in[i]=0,time[i]=0; time[S]=1,dis[S]=0,in[S]=1; int i,x,size; q[h=t=size=1]=S; for(int i=1;i<=n;i++){time[i]++,t=(t+1)%M,size++,in[q[t]=i]=1;} while(size){ for(i=g[x=q[h]],h=(h+1)%M,size--;i;i=nxt[i])if(dis[x]+w[i]<dis[v[i]]){ dis[v[i]]=dis[x]+w[i]; if(!in[v[i]]){ time[v[i]]++,t=(t+1)%M,size++,in[q[t]=v[i]]=1; if(time[v[i]]>n)return -1; } }in[x]=0; }return dis[T]; }int cas; int main(){ scanf("%d",&cas); while(cas--){ scanf("%d%d%d",&n,&m,&W); memset(v,0,sizeof(v)); memset(nxt,0,sizeof(nxt)); memset(w,0,sizeof(w)); memset(g,0,sizeof(g)); ed=0; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&e,&cost); add(u,e,cost); add(e,u,cost); } for(int i=1;i<=W;i++){ scanf("%d%d%d",&u,&e,&cost); add(u,e,-cost); } if(spfa(1)==-1)puts("YES"); else puts("NO"); }return 0; }
AOJ 2249:Road Construction
/* 建造每条道路需要的费用已经给出, 现在求在起点到每个点都是最短路的情况下的最小修路费用 考虑到最后一定是树形的,因此只要保留每个点与其父节点之间的边的费用最小值即可 在计算最短路的同时不断更新费用 */ #include <cstdio> #include <cstring> #include <queue> #include <utility> using namespace std; const int N=2000100; const int INF=~0U>>2; typedef pair<int,int>seg; priority_queue<seg,vector<seg>,greater<seg> >q; int d[N],D[N],head[N],u[N],v[N],w[N],nxt[N],cost[N],n,m,a,b,c,cc,ed=0,H,x[N],y[N]; bool vis[N]; void add(int a,int b,int c,int cos){ u[++ed]=a,v[ed]=b,w[ed]=c;cost[ed]=cos; nxt[ed]=head[u[ed]]; head[u[ed]]=ed; } void Dijkstra(int src){ memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++)d[i]=INF; d[src]=0; q.push(make_pair(d[src],src)); while(!q.empty()){ seg now=q.top(); q.pop(); int x=now.second; if(d[x]<now.first)continue; for(int e=head[x];e!=-1;e=nxt[e]) if(d[v[e]]>d[x]+w[e]){ d[v[e]]=d[x]+w[e]; D[v[e]]=cost[e]; q.push(make_pair(d[v[e]],v[e])); }else if(d[v[e]]==d[x]+w[e]){ D[v[e]]=min(cost[e],D[v[e]]); } } } int main(){ while(~scanf("%d%d",&n,&m),m+n){ memset(head,-1,sizeof(head));ed=0; memset(nxt,-1,sizeof(nxt)); while(m--){ scanf("%d%d%d%d",&a,&b,&c,&cc); add(a,b,c,cc);add(b,a,c,cc); }Dijkstra(1); int ans=0; for(int i=2;i<=n;i++)ans+=D[i]; printf("%d\n",ans); }return 0; }
AOJ 2200:Mr. Rito Post Office
/* 一张图中有陆路和水路,水路必须要有船才能走,当船开到x点时就会停在x点 一开始人和船都在1点,问按给出顺序访问一些点需要的最短时间 利用floyd可以得出只走陆路和只走水路时两点间的最短路 dp[i][j]表示走到了第i个需要访问的村庄,船停在j点的最短路,然后顺序dp更新状态即可 */ #include <cstdio> #include <algorithm> #include <cstring> #define rep(i,n) for(int i=1;i<=n;i++) using namespace std; typedef long long LL; const int INF=0x3f3f3f3f; int n,m,q,x,y,z,d[1010]; char c; int dl[210][210],ds[210][210],dp[1010][210]; int main(){ while(~scanf("%d%d",&n,&m),n+m){ rep(i,n)rep(j,n)ds[i][j]=dl[i][j]=i==j?0:INF; rep(i,m){ scanf("%d%d%d %c",&x,&y,&z,&c); if(c==‘S‘)ds[x][y]=ds[y][x]=min(ds[x][y],z); else dl[x][y]=dl[y][x]=min(dl[x][y],z); }scanf("%d",&q); rep(i,q)scanf("%d",d+i); rep(k,n)rep(i,n)rep(j,n){ ds[i][j]=min(ds[i][j],ds[i][k]+ds[k][j]); dl[i][j]=min(dl[i][j],dl[i][k]+dl[k][j]); }memset(dp,INF,sizeof(dp)); dp[1][d[1]]=0; rep(i,q)rep(j,n){ dp[i][j]=min(dp[i][j],dp[i-1][j]+dl[d[i-1]][d[i]]); rep(k,n)dp[i][k]= min((LL)dp[i][k],(LL)dp[i-1][j]+dl[d[i-1]][j]+ds[j][k]+dl[k][d[i]]); }printf("%d\n",*min_element(dp[q],dp[q]+n+1)); }return 0; }
POJ 1258:Agri-Net
/* 裸最小生成树 */ #include <cstdio> #include <algorithm> using namespace std; struct data{int x,y,c;}p[20010]; int n,m,f[110],x; bool cmp(data a,data b){return a.c<b.c;} int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);} int main(){ while(~scanf("%d",&n)){ m=0; for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){ scanf("%d",&x); if(i<j){p[++m].c=x;p[m].x=i;p[m].y=j;} }sort(p+1,p+m+1,cmp); int ans=0; for(int i=1;i<=m;i++){ if(sf(p[i].x)!=sf(p[i].y)){ ans+=p[i].c; f[sf(p[i].x)]=sf(p[i].y); } }printf("%d\n",ans); }return 0; }
POJ 2377:Bad Cowtractors
/* 裸最大生成树,需要注意判断无解的情况 */ #include <cstdio> #include <algorithm> using namespace std; struct data{int x,y,c;}p[20010]; int n,m,f[1010],x; bool cmp(data a,data b){return a.c>b.c;} int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);} int main(){ while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=m;i++){ scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c); }sort(p+1,p+m+1,cmp); int ans=0,cnt=1; for(int i=1;i<=m;i++){ if(sf(p[i].x)!=sf(p[i].y)){ ans+=p[i].c; cnt++; f[sf(p[i].x)]=sf(p[i].y); } }if(cnt!=n)puts("-1"); else printf("%d\n",ans); }return 0; }
AOJ 2224:Save your cats
/* 删除一些边使得图中没有环,求删除边的最小代价 */ #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int N=100100; int n,m,a,b,x[N],y[N],f[N]; struct data{int x,y;double c;}p[N]; bool cmp(data a,data b){return a.c<b.c;} int sf(int x){return f[x]==x?x:f[x]=sf(f[x]);} int sqr(int x){return x*x;} int main(){ while(~scanf("%d%d",&n,&m)){ double sum=0; for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]),f[i]=i; for(int i=1;i<=m;i++){ scanf("%d%d",&a,&b); double c=sqrt(sqr(x[a]-x[b])+sqr(y[a]-y[b])); sum+=c; p[i].x=a;p[i].y=b; p[i].c=-c; }sort(p+1,p+m+1,cmp); for(int i=1;i<=m;i++){ if(sf(p[i].x)!=sf(p[i].y)){ sum+=p[i].c; f[sf(p[i].x)]=sf(p[i].y); } }printf("%.3f\n",sum); }return 0; }
POJ 2395:Out of Hay
/* 求最小生成树中的最大边权 */ #include <cstdio> #include <algorithm> using namespace std; struct data{int x,y,c;}p[20010]; int n,m,f[2010],x; bool cmp(data a,data b){return a.c<b.c;} int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);} int main(){ while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=m;i++){ scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c); }sort(p+1,p+m+1,cmp); int ans=0; for(int i=1;i<=m;i++){ if(sf(p[i].x)!=sf(p[i].y)){ ans=max(ans,p[i].c); f[sf(p[i].x)]=sf(p[i].y); } }printf("%d\n",ans); }return 0; }
以上是关于挑战程序设计竞赛 2.5 它们其实都是“图”的主要内容,如果未能解决你的问题,请参考以下文章
挑战程序设计竞赛(算法和数据结构)——13.1基于加权图的两类问题的描述