[BZOJ3206][APIO2013]道路费用(最小生成树)
3206: [Apio2013]道路费用
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 568 Solved: 266
[Submit][Status][Discuss]Description
Input
第一行包含三个由空格隔开的整数N,M和K。接下来的 M行描述最开始的M 条道路这M行中的第i行包含由空格隔开的整数ai,bi和c i,表示有一条在a i和b i之间,费用为c i的双向道路。接下来的K行描述新建的K条道路。这 K行中的第i行包含由空格隔开的整数 xi和yi,表示有一条连接城镇xi和yi新道路最后一行包含N个由空格隔开的整数,其中的第j个为pj,表示从城镇j 前往城镇 1的人数。输入也满足以下约束条件。1 ≤ N ≤ 100000;1 ≤ K ≤ 20;1 ≤ M ≤ 300000;对每个i和j,1 ≤ ci, pj ≤ 10^6;注意:边权值可能相同Output
你的程序必须输出恰好一个整数到标准输出,表示能获得的最大的收入。
Sample Input
5 5 1
3 5 2
1 2 3
2 3 5
2 4 4
4 3 6
1 3
10 20 30 40 50Sample Output
400HINT
在样例中, Mr. Greedy应该将新道路(1,3)的费用设置为 5分钱。
在这个费用下,他可以选择道路(3,5),(1,2),(2,4)和(1,3)来最小化总费用,这个费用为14。
从城镇 3出发的 30个人和从城镇 5出发的 50个人将经过新道路前往城镇 1,因此他可以获得为(30+50)_5=400 分钱的最好收入。
如果我们这样做,将新道路(1,3)的费用设置为 10分钱。
根据传统的限制,Mr. Greedy必须选择(3,5),(1,2),(2,4)和(2,3),因为这是唯一费用最小的集合
。因此,在嘉年华的过程中道路(1,3)将没有任何收入。
Source
[Submit][Status][Discuss]
这种题一般不是数据结构+分类讨论,就是缩图。
1.首先把K条边全部选上,这个时候图可能仍然不连通,于是将M条原边排序,从小到大加入直到图连通。根据M条边权值互不相同可以知道,加进来的这些原边是任意一个方案都必须有的。我们将原边构成的连通块缩成点,显然图最多只有K+1个点。
2.为了保证后面枚举的复杂度,我们要找到能将K+1个点连通起来的最小的K条边,可以发现后面枚举只会使用这K条原边。
3.$O(2^K)$枚举K条边并加入图中(如果构成环则退出),剩下的将选出的K条原边从小到大加入,建出当前方案下的MST。
4.现在需要确定每条Mr. Greedy的边的权值,根据MST的圈性质可知,边<u,v>的权值肯定不能大于MST上u到v的路径中原边的最大值,依次暴力确定即可。
时间复杂度$O(m\alpha(m)+K^22^K)$,理论上可能并不能过。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=l; i<=r; i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=100010,M=300010,inf=1000000000; 8 int n,m,K,tot,tmp,cnt,rt,x,d[N],to[110],nxt[110],c[35],f[N],h[N],fa[2][N]; 9 ll sz[N],val[N],ans; 10 struct E{ int x,y,z; bool operator <(const E &a)const{ return z<a.z; }; }a[M],b[35]; 11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 12 int get(int k,int x){ return (fa[k][x]==x) ? x : fa[k][x]=get(k,fa[k][x]); } 13 void uni(int k,int x,int y){ int u=get(k,x),v=get(k,y); if (u!=v) fa[k][u]=v; } 14 15 void dfs(int x){ 16 sz[x]=val[x]; 17 for (int i=h[x],k; i; i=nxt[i]) 18 if ((k=to[i])!=fa[1][x]) 19 fa[1][k]=x,d[k]=d[x]+1,dfs(k),sz[x]+=sz[k]; 20 } 21 22 int main(){ 23 freopen("bzoj3206.in","r",stdin); 24 freopen("bzoj3206.out","w",stdout); 25 scanf("%d%d%d",&n,&m,&K); 26 rep(i,1,m) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); 27 sort(a+1,a+m+1); 28 rep(i,1,n) fa[0][i]=fa[1][i]=i; 29 rep(i,1,K) scanf("%d%d",&b[i].x,&b[i].y),uni(0,b[i].x,b[i].y); 30 rep(i,1,m){ 31 int u=get(0,a[i].x),v=get(0,a[i].y); 32 if (u!=v) fa[0][u]=v,uni(1,a[i].x,a[i].y); 33 } 34 rt=get(1,1); 35 rep(i,1,n) if (get(1,i)==i) c[++tot]=i; 36 rep(i,1,n) scanf("%d",&x),val[get(1,i)]+=x; 37 rep(i,1,m) a[i].x=get(1,a[i].x),a[i].y=get(1,a[i].y); 38 rep(i,1,K) b[i].x=get(1,b[i].x),b[i].y=get(1,b[i].y); 39 rep(i,1,m){ 40 int u=get(1,a[i].x),v=get(1,a[i].y); 41 if (u!=v) a[++tmp]=a[i],fa[1][u]=v; 42 } 43 for (int S=0; S<1<<K; S++){ 44 bool flag=0; cnt=0; 45 rep(i,1,tot) fa[1][c[i]]=h[c[i]]=0,f[c[i]]=inf,fa[0][c[i]]=c[i]; 46 rep(i,1,K) if (S&(1<<(i-1))){ 47 int u=get(0,b[i].x),v=get(0,b[i].y); 48 if (u==v) { flag=1; break; } fa[0][u]=v; 49 add(b[i].x,b[i].y); add(b[i].y,b[i].x); 50 } 51 if (flag) continue; 52 rep(i,1,K){ 53 int u=get(0,a[i].x),v=get(0,a[i].y); 54 if (u!=v) fa[0][u]=v,add(a[i].x,a[i].y),add(a[i].y,a[i].x); 55 } 56 dfs(rt); 57 rep(i,1,K){ 58 int u=a[i].x,v=a[i].y; 59 if (d[u]<d[v]) swap(u,v); 60 for (; d[u]!=d[v]; u=fa[1][u]) f[u]=min(f[u],a[i].z); 61 for (; u!=v; u=fa[1][u],v=fa[1][v]) f[u]=min(f[u],a[i].z),f[v]=min(f[v],a[i].z); 62 } 63 ll tmp=0; 64 rep(i,1,K) if (S&(1<<(i-1))){ 65 int u=b[i].x,v=b[i].y; 66 if (d[u]<d[v]) swap(u,v); 67 tmp+=sz[u]*f[u]; 68 } 69 ans=max(ans,tmp); 70 } 71 printf("%lld\n",ans); 72 return 0; 73 }