P1070 新年趣事之游戏

来源:互联网 发布:平湖市行知小学校长 编辑:程序博客网 时间:2024/05/22 00:07
次小生成树板题。
先求出最小生成树。(因为题目没有说清楚边的条数,所以我使用了prim)
然后在最小生成树上预处理出每两点间的树边的最大值。(每个点BFS一边就好了。)
然后枚举没加进去的边,每次替掉所在环上除自己外的最大值,取Min就是答案了。
复杂度O(n^2)。
代码:
#include<cstdio>#include<cstring>#include<iostream>#include<vector>#include<algorithm>#include<set>#include<bitset>#include<queue>using namespace std;#define rep(i,j,k) for(i=j;i<=k;++i)#define per(i,j,k) for(i=j;i>=k;--i)#define G getchar()#define LL long long#define pii pair<int,int>#define mkp make_pair#define X first#define Y second#define N 505#define NN 250005#define inf 1061109567int n,m;struct EDGE{int a,b,w;bool flg;}e[NN];vector<pii>v[N];bool vis[N];int Min[N],pos[N],ans;int he[N],ne[N<<1],to[N<<1],W[N<<1],tot;int q[N],Max[N][N],ans2;bool inq[N];void read(int &x){char ch=G;while(ch<48||ch>57)ch=G;for(x=0;ch>47&&ch<58;ch=G)x=x*10+ch-48;}void add(int x,int y,int z){to[++tot]=y;W[tot]=z;ne[tot]=he[x];he[x]=tot;}void BFS(int x){int Ft=1,Rr=2,u,v,i;memset(inq,0,sizeof inq);for(inq[q[1]=x]=1;Ft<Rr;)for(i=he[u=q[Ft++]];i;i=ne[i])if(!inq[v=to[i]]){inq[q[Rr++]=v]=1;Max[x][v]=max(Max[x][u],W[i]);}}int main(){int i,j,x,y,z;vector<pii>::iterator ii;read(n);read(m);rep(i,1,m){read(e[i].a);read(e[i].b);read(e[i].w);v[e[i].a].push_back(mkp(e[i].b,i));v[e[i].b].push_back(mkp(e[i].a,i));}memset(Min,63,sizeof Min);vis[x=1]=1;tot=1;rep(i,2,n){for(ii=v[x].begin();ii!=v[x].end();++ii)if(!vis[ii->X]&&e[ii->Y].w<Min[ii->X])Min[ii->X]=e[pos[ii->X]=ii->Y].w;z=inf;rep(j,1,n)if(!vis[j]&&z>Min[j])y=j,z=Min[j];if(z==inf)break;add(x,y,z);add(y,x,z);ans+=z;vis[x=y]=1;e[pos[y]].flg=1;}if(i<=n){puts("Cost: -1");return 0;}printf("Cost: %d\n",ans);if(m<n){puts("Cost: -1");return 0;}rep(i,1,n)BFS(i);ans2=inf;rep(i,1,m)if(!e[i].flg)ans2=min(ans2,e[i].w-Max[e[i].a][e[i].b]);printf("Cost: %d\n",ans2+ans);return 0;}

原创粉丝点击