HDU 6081 度度熊的王国战略(全局最小割堆优化)

Problem Description
度度熊国王率领着喵哈哈族的勇士,准备进攻哗啦啦族。
哗啦啦族是一个强悍的民族,里面有充满智慧的谋士,拥有无穷力量的战士。
所以这一场战争,将会十分艰难。
为了更好的进攻哗啦啦族,度度熊决定首先应该从内部瓦解哗啦啦族。
第一步就是应该使得哗啦啦族内部不能同心齐力,需要内部有间隙。
哗啦啦族一共有n个将领,他们一共有m个强关系,摧毁每一个强关系都需要一定的代价。
现在度度熊命令你需要摧毁一些强关系,使得内部的将领,不能通过这些强关系,连成一个完整的连通块,以保证战争的顺利进行。
请问最少应该付出多少的代价。

Input
本题包含若干组测试数据。
第一行两个整数n,m,表示有n个将领,m个关系。
接下来m行,每行三个整数u,v,w。表示u将领和v将领之间存在一个强关系,摧毁这个强关系需要代价w

数据范围:
2<=n<=3000
1<=m<=100000
1<=u,v<=n
1<=w<=1000

Output
对于每组测试数据,输出最小需要的代价。

Sample Input
2 1
1 2 1
3 3
1 2 5
1 2 4
2 3 3

Sample Output
1
3

题意

如上

题解

做法1.求全局最小割,由于点多边少,得用SW+堆优化(nmlogm)

做法2.S=1,随机T,求最小割,考虑到两个集合a和b,1肯定在a或b集合,也就是说随机的点只要在另外一个集合上,就有可能跑出最小割,特别要注意的是如果2999+1或者2998+2,会被卡到,所以可以特判掉这两种情况,另外>=3个点的概率还是挺高的(雾)

代码

SW+堆优化8080ms

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=3010;
 5 const int maxm=2e5+5;
 6 const int INF=0x3f3f3f3f;
 7 
 8 int FIR[maxn],TO[maxm],NEXT[maxm],W[maxm],tote;
 9 bool vis[maxn];
10 int F[maxn],link[maxn],wage[maxn];
11 int n,m;
12 
13 void add(int u,int v,int w)
14 {
15     TO[tote]=v;
16     W[tote]=w;
17     NEXT[tote]=FIR[u];
18     FIR[u]=tote++;
19     
20     TO[tote]=u;
21     W[tote]=w;
22     NEXT[tote]=FIR[v];
23     FIR[v]=tote++;
24 }
25 int Find(int x)
26 {
27     return x==F[x]?x:F[x]=Find(F[x]);
28 }
29 void Join(int u,int v)
30 {
31     int p=u;
32     while(link[p]!=-1)p=link[p];
33     link[p]=v;
34     F[v]=u;
35 }
36 int MinCut(int cnt,int &s,int &t)
37 {
38     memset(wage,0,sizeof wage);
39     memset(vis,false,sizeof vis);
40     priority_queue< pair<int,int> >q;
41     t=1;
42     while(--cnt)
43     {
44         vis[s=t]=true;
45         for(int u=s;u!=-1;u=link[u])
46         {
47             for(int p=FIR[u];p!=-1;p=NEXT[p])
48             {
49                 int v=Find(TO[p]);
50                 if(!vis[v])
51                     q.push(make_pair(wage[v]+=W[p],v));
52             }
53         }
54         t=0;
55         while(!t)
56         {
57             if(q.empty())return 0;
58             pair<int,int> pa=q.top();q.pop();
59             if(wage[pa.second]==pa.first)
60                 t=pa.second;
61         }
62     }
63     return wage[t];
64 }
65 int Stoer_Wagner()
66 {
67     int res=INF;
68     for(int i=n,s,t;i>1;i--)
69     {
70         res=min(res,MinCut(i,s,t));
71         if(res==0)break;
72         Join(s,t);
73     }
74     return res;
75 }
76 void init()
77 {
78     tote=0;
79     for(int i=1;i<=n;i++)FIR[i]=link[i]=-1,F[i]=i;
80 }
81 int main()
82 {
83     while(scanf("%d%d",&n,&m)!=EOF)
84     {
85         init();
86         for(int i=0,u,v,w;i<m;i++)
87         {
88             scanf("%d%d%d",&u,&v,&w);
89             add(u,v,w);
90         }
91         printf("%d\n",Stoer_Wagner());
92     }
93     return 0;
94 }

随机算法2402ms

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=3005;
 5 const int maxm=2e5+5;//至少总M*2
 6 const int INF=0x3f3f3f3f;
 7 
 8 int TO[maxm],CAP[maxm],NEXT[maxm],tote;
 9 int FIR[maxn],gap[maxn],cur[maxn],d[maxn],q[400000],u[maxm],v[maxm],w[maxm];
10 int n,m,S,T;
11 
12 void add(int u,int v,int cap)
13 {
14     //printf("i=%d %d %d %d\n",tote,u,v,cap);
15     TO[tote]=v;
16     CAP[tote]=cap;
17     NEXT[tote]=FIR[u];
18     FIR[u]=tote++;
19     
20     TO[tote]=u;
21     CAP[tote]=0;
22     NEXT[tote]=FIR[v];
23     FIR[v]=tote++;
24 }
25 void bfs()
26 {
27     memset(gap,0,sizeof gap);
28     memset(d,0,sizeof d);
29     ++gap[d[T]=1];
30     for(int i=1;i<=n;++i)cur[i]=FIR[i];
31     int head=1,tail=1;
32     q[1]=T;
33     while(head<=tail)
34     {
35         int u=q[head++];
36         for(int v=FIR[u];v!=-1;v=NEXT[v])
37             if(!d[TO[v]])
38                 ++gap[d[TO[v]]=d[u]+1],q[++tail]=TO[v];
39     }
40 }
41 int dfs(int u,int fl)
42 {
43     if(u==T)return fl;
44     int flow=0;
45     for(int &v=cur[u];v!=-1;v=NEXT[v])
46         if(CAP[v]&&d[u]==d[TO[v]]+1)
47         {
48             int Min=dfs(TO[v],min(fl,CAP[v]));
49             flow+=Min,fl-=Min,CAP[v]-=Min,CAP[v^1]+=Min;
50             if(!fl)return flow;
51         }
52     if(!(--gap[d[u]]))d[S]=n+1;
53     ++gap[++d[u]],cur[u]=FIR[u];
54     return flow;
55 }
56 int ISAP()
57 {
58     bfs();
59     int ret=0;
60     while(d[S]<=n)ret+=dfs(S,INF);
61     return ret;
62 }
63 void init()
64 {
65     tote=0;
66     memset(FIR,-1,sizeof FIR);
67 }
68 int main()
69 {
70     srand(time(NULL));
71     while(scanf("%d%d",&n,&m)!=EOF)
72     {
73         int wage[maxn]={0};
74         for(int i=0;i<m;i++)
75         {
76             scanf("%d%d%d",&u[i],&v[i],&w[i]);
77             wage[u[i]]+=w[i];
78             wage[v[i]]+=w[i];
79         }
80         int sj[maxn];
81         for(int i=1;i<n;i++)sj[i]=i+1;
82         random_shuffle(sj+1,sj+n);
83         int ans=1e9;
84         for(int i=1;i<=n;i++)ans=min(ans,wage[i]);
85         if(n!=2)for(int i=0;i<m;i++)ans=min(ans,wage[u[i]]+wage[v[i]]-2*w[i]);
86         S=1;
87         for(int i=1;i<=min(500,n-1);i++)
88         {
89             T=sj[i];
90             init();
91             for(int j=0;j<m;j++)
92                 add(u[j],v[j],w[j]),add(v[j],u[j],w[j]);    
93             ans=min(ans,ISAP());
94         }
95         printf("%d\n",ans);
96     }
97     return 0;
98 }

 

posted on 2018-09-07 22:38  大桃桃  阅读(375)  评论(0编辑  收藏  举报

导航