题目链接:http://www.bnuoj.com/bnuoj/problem_show.php?pid=26586
题意:给一个图,每条边有一个权值。要你求选择一棵树,权值和为sum,然后在树上选择一条边权值为w,然后使得sum-2*w最小。
首先求一遍最小生成树,然后求出每两个点之间的最小瓶颈路,然后枚举边就行了。。
1 //STATUS:C++_AC_916MS_30048KB 2 #include <cmath> 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 #define mem(a,b) memset(a,b,sizeof(a)) 9 typedef long long LL; 10 11 const int N=2010; 12 13 struct Edge{ 14 int u,v,w; 15 }e[1000010],et[2000010]; 16 int first[N],next[2000010]; 17 int p[N],vis[N],d[N][N]; 18 bool mst[1000010]; 19 int n,m,mt; 20 21 void adde(int a,int b,int c) 22 { 23 et[mt].u=a,et[mt].v=b,et[mt].w=c; 24 next[mt]=first[a];first[a]=mt++; 25 et[mt].u=b,et[mt].v=a,et[mt].w=c; 26 next[mt]=first[b];first[b]=mt++; 27 } 28 29 int cmp(const Edge& a,const Edge& b) 30 { 31 return a.w<b.w; 32 } 33 34 int find(int x){return p[x]==x?x:p[x]=find(p[x]);} 35 36 int Kruskal() 37 { 38 int i,j,x,y,sum=0,cnt=0; 39 for(i=1;i<=n;i++)p[i]=i; 40 sort(e,e+m,cmp); 41 mem(mst,0); 42 for(i=0;i<m;i++){ 43 x=find(e[i].u); 44 y=find(e[i].v); 45 if(x!=y){ 46 cnt++; 47 sum+=e[i].w; 48 p[y]=x; 49 mst[i]=true; 50 } 51 } 52 if(cnt<n-1)return -1; 53 return sum; 54 } 55 56 int dfs(int& s,int u,int fa,int hig) 57 { 58 int i,v; 59 for(i=first[u];i!=-1;i=next[i]){ 60 v=et[i].v; 61 if(v==fa)continue; 62 d[s][v]=max(hig,et[i].w); 63 dfs(s,v,u,d[s][v]); 64 } 65 return 0; 66 } 67 68 int main(){ 69 // freopen("in.txt","r",stdin); 70 int i,j; 71 while(~scanf("%d%d",&n,&m)) 72 { 73 for(i=0;i<m;i++){ 74 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 75 } 76 77 int sum; 78 if((sum=Kruskal())==-1){ 79 printf("disconnected "); 80 continue; 81 } 82 mem(first,-1);mt=0; 83 for(i=0;i<m;i++){ 84 if(mst[i]){ 85 adde(e[i].u,e[i].v,e[i].w); 86 } 87 } 88 mem(d,0); 89 for(i=1;i<=n;i++){ 90 dfs(i,i,-1,0); 91 } 92 int ans=0x7FFFFFFF; 93 for(i=0;i<m;i++){ 94 ans=min(ans,sum-d[e[i].u][e[i].v]-e[i].w); 95 } 96 97 printf("%d ",ans); 98 } 99 return 0; 100 }