hdu 4067 Random Maze - 费用流+思维

版权声明:本博客内容基本为原创,如有问题欢迎联系,未经允许请勿转载 https://blog.csdn.net/qq_41955236/article/details/82084121

Random Maze

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1640    Accepted Submission(s): 665


 

Problem Description

In the game “A Chinese Ghost Story”, there are many random mazes which have some characteristic:
1.There is only one entrance and one exit.
2.All the road in the maze are unidirectional.
3.For the entrance, its out-degree = its in-degree + 1.
4.For the exit, its in-degree = its out-degree + 1.
5.For other node except entrance and exit, its out-degree = its in-degree.


There is an directed graph, your task is removing some edge so that it becomes a random maze. For every edge in the graph, there are two values a and b, if you remove the edge, you should cost b, otherwise cost a.
Now, give you the information of the graph, your task if tell me the minimum cost should pay to make it becomes a random maze.
   

Input

The first line of the input file is a single integer T.
The rest of the test file contains T blocks.
For each test case, there is a line with four integers, n, m, s and t, means that there are n nodes and m edges, s is the entrance's index, and t is the exit's index. Then m lines follow, each line consists of four integers, u, v, a and b, means that there is an edge from u to v.
2<=n<=100, 1<=m<=2000, 1<=s, t<=n, s != t. 1<=u, v<=n. 1<=a, b<=100000

 

Output

For each case, if it is impossible to work out the random maze, just output the word “impossible”, otherwise output the minimum cost.(as shown in the sample output)

 

Sample Input

 

2 2 1 1 2 2 1 2 3 5 6 1 4 1 2 3 1 2 5 4 5 5 3 2 3 3 2 6 7 2 4 7 6 3 4 10 5

 

Sample Output

 

Case 1: impossible Case 2: 27


题意:

     给出n个点,m条边,入口s和出口t,对于每条边有两个值a,b,如果保留这条边需要花费a;否则,移除这条边需要花费b。
              要求用最小费用构造一个满足以下条件的有向图:
              1.只有一个入口和出口
              2.所有路都是唯一方向
              3.对于入口s,它的出度 = 它的入度 + 1
              4.对于出口t,它的入度 = 它的出度 + 1
              5.除了s和t外,其他点的入度 = 其出度
              如果可以构造的出来,输出最小费用;否则输出impossib。

做法:

         参考了大神的题解。这道题的核心在于贪心构图,然后用费用流去跑最小的修改的值。开始时的贪心构图即不管入度和出度,我们总是选用费用最小的那个边,来保证一开始的时候我们的费用一定为最小。
          对于每条边u v a b,如果a <= b,连边v->u!!!!这里是重点!容量为1,费用为a-b,这样连边的意义是我们初始选择保留u->v这条边,建立反边是为了保证之后的费用不会流过改边,如果会流过则一定会引起改变(这里是个人的理解,表示有点对于反边的建立有点糊涂)。
         否则如果a > b,连边u->v,容量为1,费用为b-a,这样连边的意义是我们初始选择删除这条边,如果还需要这条边,那么费用流会跑过这里。所以in[],out[]没有改变,sum+=b。

        新建超级源汇S,T。  对于每个点i, 如果in[i] > out[i] . 建边S->i, 权值为0, 流量为in[i] – out[i];  否则建边 i->T ,权值为0, 流量为out[i] – in[i];
              
              下面是大神的博客里的解释:

             这里说下算法是如何进行调整的:
              举个简单的例子,假如某一个点i,in[i] > out[i],说明当前的入度大于当前的出度,那么我们可以这样调整:把之前删除的以i为起点的边添加回来 或者 把之前保留的以i为终点的边删除,现在边的费用其实是改变边状态所需要额外付的费用,而最小费用流算法就可以帮我选择最小的调整费用,也就是那个mincost。
              所以最后的总费用ans = 初始费用sum + 最小调整费用mincost。


#include <cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn=400;
const int maxm=200000;
const int inf=0x3f3f3f3f;
int dis[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt,in[maxn],out[maxn];
int n,m,sp,tp;
struct node{
    int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
    e[cnt].to=to; e[cnt].cap=cap;
    e[cnt].cost=cost; e[cnt].next=head[from];
    head[from]=cnt++;

    e[cnt].to=from; e[cnt].cap=0;
    e[cnt].cost=-cost; e[cnt].next=head[to];
    head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
    queue<int> q;
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    dis[s]=0;  q.push(s);
    vis[s]=1;
    int d=inf;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
                dis[v]=dis[u]+e[i].cost;
                pre[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(dis[t]==inf){
        return false;
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        d=min(d,e[i].cap);
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        e[i].cap-=d;
        e[i^1].cap+=d;
        cost+=e[i].cost*d;
    }
    flow+=d;
    return true;
}
int mcmf(int s,int t,int &cost){
    int flow=0;
    cost=0;
    while(spfa(s,t,flow,cost)){
        //cout<<flow<<" "<<cost<<endl;
    }
    return flow;
}
int main(){
    int t,st,en,x,y,a,b,cas=0;
    cin>>t;
    while(t--){
        memset(head,-1,sizeof(head));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        cnt=0;
        int ans=0;
        scanf("%d%d%d%d",&n,&m,&st,&en);
        sp=0,tp=n+1;

        for(int i=0;i<m;i++){
            scanf("%d%d%d%d",&x,&y,&a,&b);
            if(a<=b){
                add(y,x,1,b-a);
                in[y]++,out[x]++;
                ans+=a;
            }
            else {
                add(x,y,1,a-b);
                ans+=b;
            }
        }
        in[st]++,out[en]++;
        int ck=0;
        for(int i=1;i<=n;i++){
            if(in[i]>out[i]){
                add(sp,i,in[i]-out[i],0);
                ck+=in[i]-out[i];
            }
            else {
                add(i,tp,out[i]-in[i],0);
            }
        }
        int aim=0;
        int now=mcmf(sp,tp,aim);
        if(now!=ck){
            printf("Case %d: impossible\n",++cas);
        }
        else {
            ans+=aim;
            printf("Case %d: %d\n",++cas,ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/82084121
今日推荐