BZOJ 1601 [Usaco2008 Oct]灌水 (建图+mst)
题意:
300个坑,每个坑能从别的坑引水,或者自己出水,i从j饮水有个代价,每个坑自己饮水也有代价,问让所有坑都有谁的最少代价
思路:
先建一个n的完全图,然后建一个超级汇点,对每个点连w[i],跑mst,这样就能保证所有坑联通,并且至少有一个坑有水
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 //#define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 2e6+100; const int maxm = 2e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int p[333][333]; int w[333]; int n; int f[maxn]; int find(int x){ return f[x]==x?x:f[x]=find(f[x]); } struct node{ int x, y; int w; }edge[maxn]; bool cmp(node a, node b){ return a.w<b.w; } int tot; int add(int x, int y, int w){ edge[++tot].x=x; edge[tot].y=y; edge[tot].w=w; } int main(){ scanf("%d", &n); for(int i = 1; i <= n; i++){ scanf("%d", &w[i]); add(0,i,w[i]); } for(int i = 1; i <= n; i++){ for(int j = 1; j <= n; j++){ scanf("%d", &p[i][j]); add(i,j,p[i][j]); } } for(int i = 0; i <= n; i++)f[i]=i; sort(edge+1, edge+1+tot,cmp); int cnt = 0; int ans = 0; for(int i = 1; i <= tot; i++){ int x = edge[i].x; int y = edge[i].y; int w = edge[i].w; int t1 = find(x); int t2 = find(y); if(t1 != t2){ f[t1] = t2; ans+=w; cnt++; } if(cnt==n)break; } printf("%d",ans); return 0; } /* 4 5 4 4 3 0 2 2 2 2 0 3 3 2 3 0 4 2 3 4 0 */