Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9941 Accepted Submission(s): 2827
Mean:
好久没刷水题了。。。
给你一个有向图,其中某些边是连接的,现在要你找一棵最小生成树。
analyse:
先用并查集来合并已经连通的边,然后在使用kruskal来求最小生成树,注意这儿有一个剪枝,因为这题的边很多,所以我们不需要全部判断,根据最小生成树的性质可知,我们只需要找出n-1条边即可。
Time complexity:O(n)
Source code:
//Memory Time // 5644K 241MS //by : Snarl_jsb #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<vector> #include<queue> #include<stack> #include<iomanip> #include<string> #include<climits> #include<cmath> #define MAXV 520 #define MAXE 25010 #define LL long long using namespace std; int T,n,m,k; struct Node { int s,e,val; } graph[MAXE]; int father[MAXV]; void scan(int& x){ x = 0; char c = getchar (); while (!(c>='0' && c<='9' || c=='-')) c = getchar (); while (c >= '0' && c <= '9'){ x = x * 10 + c - '0'; c = getchar (); } } int Find(int x) { return x==father[x]?x:father[x]=Find(father[x]); } bool cmp(Node a,Node b) { return a.val<b.val; } int kruskal() { int ans=0; int cnt=0; sort(graph+1,graph+1+m,cmp); for(int i=1;i<=n;i++) if(father[i]==i) cnt++; for(int i=1;i<=m&&cnt>1;i++) { int x=Find(graph[i].s); int y=Find(graph[i].e); if(x!=y) { father[x]=y; ans+=graph[i].val; cnt--; } } if(cnt==1) return ans; else return -1; } int main() { // freopen("cin.txt","r",stdin); // freopen("cout.txt","w",stdout); scan(T); while(T--) { scan(n); scan(m); scan(k); for(int i=1;i<=m;i++) { scan(graph[i].s); scan(graph[i].e); scan(graph[i].val); } for(int i=0;i<=n;i++) father[i]=i; int cnt,fa,son; while(k--) { scan(cnt); scan(fa); fa=Find(fa); while(--cnt) { scan(son); father[Find(son)]=fa; } } int mincost=kruskal(); printf("%d\n",mincost); } return 0; }