HDU4067 Random Maze(最小费用最大流)

题目大概说,给一张图,删除其中一些单向边,使起点s出度比入度多1,终点t入度比出度多1,其他点出度等于入度。其中删除边的费用是bi,保留边的费用是ai,问完成要求最小的费用是多少。

一开始我想到和混合图欧拉回路(POJ1637)的类似构造方法:

  • 假设所有边一开始都是保留的,算出各个点的入度和出度,另外s点的出度-1,t点的入度-1;
  • 然后把出度-入度等于正数的点源点向其连一条容量为出度-入度的边,等于负数的点其向汇点连一条容量为入度-出度的边
  • 这样就是要通过删除边使那些与源汇相连的边满流,这样就满足各个点度的要求;而删除一条边<u,v>会使u的出度-1,v的入度-1,这样在容量网络中由u向v连容量1费用bi-ai的边
  • Σai-MCMF就是答案

不过这样是错的= =而且因为负环死循环TLE了。我试图想拆点消除负环,发现两端点都与源点或汇点相连的边都不起作用,觉得怪怪的好像不大对,提交果然是WA的。

正确的做法是:一开始不是假设所有边都是保留的,而是贪心地先确定最少的费用,即如果ai<bi则保留否则删除!

然后接下去的做法也是类似的,我就不赘述了。。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 using namespace std;
  6 #define INF (1<<30)
  7 #define MAXN 111
  8 #define MAXM 8888
  9 struct Edge{
 10     int u,v,cap,cost,next;
 11 }edge[MAXM];
 12 int vs,vt,NV,NE,head[MAXN];
 13 void addEdge(int u,int v,int cap,int cost){
 14     edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
 15     edge[NE].next=head[u]; head[u]=NE++;
 16     edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
 17     edge[NE].next=head[v]; head[v]=NE++;
 18 }
 19 int d[MAXN],pre[MAXN];
 20 bool vis[MAXN];
 21 bool SPFA(){
 22     for(int i=0; i<NV; ++i){
 23         d[i]=INF; vis[i]=0;
 24     }
 25     d[vs]=0; vis[vs]=1;
 26     queue<int> que;
 27     que.push(vs);
 28     while(!que.empty()){
 29         int u=que.front(); que.pop();
 30         for(int i=head[u]; i!=-1; i=edge[i].next){
 31             int v=edge[i].v;
 32             if(edge[i].cap && d[v]>d[u]+edge[i].cost){
 33                 d[v]=d[u]+edge[i].cost;
 34                 pre[v]=i;
 35                 if(!vis[v]){
 36                     vis[v]=1;
 37                     que.push(v);
 38                 }
 39             }
 40         }
 41         vis[u]=0;
 42     }
 43     return d[vt]!=INF;
 44 }
 45 int tot;
 46 int MCMF(){
 47     int res=0,mxflow=0;
 48     while(SPFA()){
 49         int flow=INF,cost=0;
 50         for(int u=vt; u!=vs; u=edge[pre[u]].u){
 51             flow=min(flow,edge[pre[u]].cap);
 52         }
 53         mxflow+=flow;
 54         for(int u=vt; u!=vs; u=edge[pre[u]].u){
 55             edge[pre[u]].cap-=flow;
 56             edge[pre[u]^1].cap+=flow;
 57             cost+=flow*edge[pre[u]].cost;
 58         }
 59         res+=cost;
 60     }
 61     if(tot!=mxflow) return INF;
 62     return res;
 63 }
 64 int u[2222],v[2222],w1[2222],w2[2222];
 65 int deg[MAXN];
 66 int main(){
 67     int T,n,m,s,t;
 68     scanf("%d",&T);
 69     for(int cse=1; cse<=T; ++cse){
 70         scanf("%d%d%d%d",&n,&m,&s,&t);
 71         int res=0;
 72         memset(deg,0,sizeof(deg));
 73         --deg[s]; ++deg[t];
 74         for(int i=0; i<m; ++i){
 75             scanf("%d%d%d%d",u+i,v+i,w1+i,w2+i);
 76             if(w1[i]<w2[i]){
 77                 ++deg[u[i]];
 78                 --deg[v[i]];
 79                 res+=w1[i];
 80             }else{
 81                 res+=w2[i];
 82             }
 83         }
 84         tot=0;
 85         vs=0; vt=n+1; NV=vt+1; NE=0;
 86         memset(head,-1,sizeof(head));
 87         for(int i=1; i<=n; ++i){
 88             if(deg[i]>0) addEdge(vs,i,deg[i],0),tot+=deg[i];
 89             else addEdge(i,vt,-deg[i],0);
 90         }
 91         for(int i=0; i<m; ++i){
 92             if(w1[i]<w2[i]){
 93                 addEdge(u[i],v[i],1,w2[i]-w1[i]);
 94             }else{
 95                 addEdge(v[i],u[i],1,w1[i]-w2[i]);
 96             }
 97         }
 98         int tmp=MCMF();
 99         if(tmp==INF) printf("Case %d: impossible\n",cse);
100         else printf("Case %d: %d\n",cse,res+tmp);
101     }
102     return 0;
103 }

 

posted @ 2016-04-15 15:06  WABoss  阅读(358)  评论(0编辑  收藏  举报