题意:一个无向带权图,候选方案是至少两个点的连通子图,连通子图里的边权的最小值比边界边的最大值大(边界边是一个点在这个子图里,另一个点不在这个子图里)!.问你所有满足候选方案的子图的顶点个数总和是多少?
分析:kruskal的思想,先将边权大的连接,然后判断是否满足,,,依次连接即可!
// File Name: 1265.cpp // Author: Zlbing // Created Time: 2013/5/31 16:52:09 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=5000+50; int n,m; struct Edge{ int u,v,cost; bool operator <(const Edge e)const{ return cost>e.cost; } }; vector<int>G[MAXN],GG[MAXN]; vector<Edge> edges,ee; int f[MAXN]; int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } int num[MAXN]; bool check(int x) { int minn=INF,maxn=0; for(int i=1;i<=n;i++) { int fu=find(i); if(fu!=x)continue; for(int j=0;j<GG[i].size();j++) { Edge e=ee[GG[i][j]]; int v=e.v; int fv=find(v); if(fv==fu) { minn=min(minn,e.cost); } else{ maxn=max(maxn,e.cost); } } } if(minn>maxn)return true; else return false; } int kruskal(){ for(int i=0;i<=n;i++)f[i]=i; for(int i=0;i<=n;i++)num[i]=1; sort(edges.begin(),edges.end()); int ans=0; for(int i=0;i<m;i++) { Edge e=edges[i]; int fu=find(e.u); int fv=find(e.v); if(fu!=fv) { f[fu]=fv; num[fv]+=num[fu]; if(check(fv)){ ans+=num[fv]; } } } return ans; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); REP(i,0,n){ G[i].clear(); GG[i].clear(); } edges.clear(); int a,b,c; REP(i,1,m) { scanf("%d%d%d",&a,&b,&c); edges.push_back((Edge){a,b,c}); int mm=edges.size(); G[a].push_back(mm-1); ee.push_back((Edge){a,b,c}); ee.push_back((Edge){b,a,c}); mm=ee.size(); GG[a].push_back(mm-2); GG[b].push_back(mm-1); } int ans=kruskal(); printf("%d\n",ans); } return 0; }