hdu 3251(最小割)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3251

思路:选择1为源点,n+1为汇点,然后原图中每条边为新图的边,容量为边权,最后将每个可以选择的点与汇点连接,容量为点权,这样跑一遍最大流之后,求出最小割,然后所有的总收益减去最小割就是可能的最大收益了。

View Code
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 using namespace std;
  5 #define MAXN 1111
  6 #define MAXM 444444
  7 #define inf 1<<30
  8 
  9 struct Edge{
 10     int v,cap,next;
 11 }edge[MAXM];
 12 
 13 struct Rode{
 14     int st,ed;
 15 }rode[MAXM];
 16 
 17 int head[MAXN];
 18 int pre[MAXN];
 19 int cur[MAXN];
 20 int level[MAXN];
 21 int gap[MAXN];
 22 int NE,NV,n,m,vs,vt,f;
 23 bool mark[MAXN];
 24 int num[MAXM];
 25 
 26 int SAP(int vs,int vt){
 27     memset(pre,-1,sizeof(pre));
 28     memset(level,0,sizeof(level));
 29     memset(gap,0,sizeof(gap));
 30     for(int i=0;i<=NV;i++)cur[i]=head[i];
 31     int u=pre[vs]=vs,maxflow=0,aug=-1;
 32     gap[0]=NV;
 33     while(level[vs]<NV){
 34 loop:
 35         for(int &i=cur[u];i!=-1;i=edge[i].next){
 36             int v=edge[i].v;
 37             if(edge[i].cap&&level[u]==level[v]+1){
 38                 aug==-1?aug=edge[i].cap:aug=min(aug,edge[i].cap);
 39                 pre[v]=u;
 40                 u=v;
 41                 if(v==vt){
 42                     maxflow+=aug;
 43                     for(u=pre[u];v!=vs;v=u,u=pre[u]){
 44                         edge[cur[u]].cap-=aug;
 45                         edge[cur[u]^1].cap+=aug;
 46                     }
 47                     aug=-1;
 48                 }
 49                 goto loop;
 50             }
 51         }
 52         int minlevel=NV;
 53         for(int i=head[u];i!=-1;i=edge[i].next){
 54             int v=edge[i].v;
 55             if(edge[i].cap&&minlevel>level[v]){
 56                 cur[u]=i;
 57                 minlevel=level[v];
 58             }
 59         }
 60         if(--gap[level[u]]==0)break;
 61         level[u]=minlevel+1;
 62         gap[level[u]]++;
 63         u=pre[u];
 64     }
 65     return maxflow;
 66 }
 67 
 68 void Insert(int u,int v,int cap,int cc=0){
 69     edge[NE].v=v;edge[NE].cap=cap;
 70     edge[NE].next=head[u];head[u]=NE++;
 71 
 72     edge[NE].v=u;edge[NE].cap=cc;
 73     edge[NE].next=head[v];head[v]=NE++;
 74 }
 75 
 76 void dfs(int u){
 77     mark[u]=true;
 78     for(int i=head[u];i!=-1;i=edge[i].next){
 79         int v=edge[i].v;
 80         if(!mark[v]&&edge[i].cap>0){
 81             dfs(v);
 82         }
 83     }
 84 }
 85     
 86 
 87 int main(){
 88     int _case,u,v,w,sum,ans,t=1,count;
 89     scanf("%d",&_case);
 90     while(_case--){
 91         scanf("%d%d%d",&n,&m,&f);
 92         vs=1,vt=n+1,NE=0,NV=vt,sum=0,count=0;
 93         memset(head,-1,sizeof(head));
 94         memset(mark,false,sizeof(mark));
 95         for(int i=1;i<=m;i++){
 96             scanf("%d%d%d",&u,&v,&w);
 97             rode[i].st=u,rode[i].ed=v;
 98             Insert(u,v,w);
 99         }
100         for(int i=1;i<=f;i++){
101             scanf("%d%d",&u,&w);
102             Insert(u,vt,w);
103             sum+=w;
104         }
105         printf("Case %d: %d\n",t++,sum-SAP(vs,vt));
106         dfs(1);
107         for(int i=1;i<=m;i++){
108             if(mark[rode[i].st]&&!mark[rode[i].ed]){
109                 num[count++]=i;
110             }
111         }
112         printf("%d",count);
113         for(int i=0;i<count;i++)printf(" %d",num[i]);
114         puts("");
115     }
116     return 0;
117 }
118 
119 
120 
121 
122             

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值