HDU 4067 Random Maze

来源:互联网 发布:跳跃网络次元大作战 编辑:程序博客网 时间:2024/05/16 19:50
题意:给出一个有n个点m条边的有向图,现在要从图中删去一些边使得图满足以下条件:
1.图中只有一个入口(s)和一个出口(t)
2.所以边都是单向的(这个原图已经保证了)
3.对入口(s)而言,其出度=入度+1
4.对出口(t)而言,其入度=出度+1
5.对入口(s)、出口(t)以外的点,其入度=出度

而对图中每条边,保留这条边或者删去这条边都有相应的花费,分别为a、b,求使得该图满足条件的最小花费。


解法:
重新为每个边建立权值!
1.如果有边(u,v,a,b) 并且a<=b,那么建立边(v,u,1,b-a) sum+=a,如果要恢复此边需花费 b-a 的费用;in[u]++,out[v]++;
2.如果有边(u,v,a,b) 并且a>b,那么建立边(u,v,1,a-b) sum+=b,如果要删除此边需花费 a-b 的费用;
3.另需t和s 建立一条虚边,in[s]++,out[t]++;
最后建立一个超级源点S 和超级汇点T,则如果对于点 i in[i]>out[i] 那么建立边(S,i,in[i]-out[i],0);
相反 建立边(i,T,out[i]-in[i],0);
最小费用最大流后,如果max_flow=到汇点t所有容量只和 答案即为:sum+max_flow;

否则 impossible;

#include <algorithm>#include <iostream>#include <iomanip>#include <cstring>#include <climits>#include <complex>#include <fstream>#include <cassert>#include <cstdio>#include <bitset>#include <vector>#include <deque>#include <queue>#include <stack>#include <ctime>#include <set>#include <map>#include <cmath>#define CLR(x,y) memset(x,y,sizeof(x))#define mp(x,y) make_pair(x,y)#define eps 1e-9#define INF 0x3f3f3f3fusing namespace std;typedef long long ll;typedef long double ld;typedef pair<ll, ll> pll;typedef complex<ld> point;typedef pair<int, int> pii;typedef pair<pii, int> piii;template<class T>inline bool read(T &n){    T x = 0, tmp = 1;    char c = getchar();    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();    if(c == EOF) return false;    if(c == '-') c = getchar(), tmp = -1;    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();    n = x*tmp;    return true;}template <class T>inline void write(T n){    if(n < 0)    {        putchar('-');        n = -n;    }    int len = 0,data[20];    while(n)    {        data[len++] = n%10;        n /= 10;    }    if(!len) data[len++] = 0;    while(len--) putchar(data[len]+48);}//-----------------------------------const int M=5010;const int N=111;int in[N];          //入度和出度的差int n,m,s,t;struct Graph{    struct node    {        int v,next,w,flow;        node() {};        node(int a,int b,int c,int d)        {            next=a;            v=b;            w=c;            flow=d;        }    } E[2*M];    int head[N],pre[N],dis[N];    int beg,end,flow,cost;    bool h[N];    int path[N];    int NE,NV;    void resize(int n)    {        this->NV=n;    }    void init(int n)    {        NE=0;        NV=n;        memset(head,-1,sizeof(int)*(n+10));    }    void insert(int u,int v,int flow,int w)    {        E[NE]=node(head[u],v,w,flow);        head[u]=NE++;        E[NE]=node(head[v],u,-w,0);        head[v]=NE++;    }    bool update(int u,int v,int w)    {        if(dis[u]+w<dis[v])        {            dis[v]=dis[u]+w;            return true;        }        return false;    }    bool spfa()    {        CLR(pre,-1);        CLR(h,0);        for(int i=0; i<=NV; i++)            dis[i]=INF;        dis[beg]=0;        queue<int> q;        q.push(beg);        while(!q.empty())        {            int u=q.front();            q.pop();            h[u]=0;            for(int i=head[u]; i!=-1; i=E[i].next)            {                int v=E[i].v;                if(E[i].flow>0&&update(u,v,E[i].w))                {                    pre[v]=u;                    path[v]=i;                    if(!h[v])                    {                        h[v]=1;                        q.push(v);                    }                }            }        }        if(pre[end]==-1)            return false;        return true;    }    int mincost_maxflow(int s,int t)    {        this->beg=s;        this->end=t;        flow=0,cost=0;        while(spfa())        {            int Min=INT_MAX;            for(int i=end; i!=beg; i=pre[i])                if(Min>E[path[i]].flow)                    Min=E[path[i]].flow;            for(int i=end; i!=beg; i=pre[i])            {                E[path[i]].flow-=Min;                E[path[i]^1].flow+=Min;            }            flow+=Min;            cost+=dis[end];        }        return cost;    }} g;int main(){    int T,cas=1;    read(T);    while(T--)    {        read(n),read(m),read(s),read(t);        g.init(n+2);        memset(in,0,sizeof(in));        in[s]++,in[t]--;        int u,v,a,b,ss=0,tt=n+1,sum=0,cnt=0;        for(int i=1;i<=m;i++)        {            read(u),read(v),read(a),read(b);            if(a>=b)            {                g.insert(u,v,1,a-b);        //  删除(如果流过则不删)                sum+=b;            }            else            {                g.insert(v,u,1,b-a);        //  不删除(如果流过则删除,加一条反边中和入度出度)                sum+=a;                in[u]--,in[v]++;            }        }        for(int i=1;i<=n;i++)               //  保留入度,计算出度        {            if(in[i]>0)                g.insert(ss,i,in[i],0);            else            {                g.insert(i,tt,-in[i],0);                cnt+=-in[i];            }        }        sum+=g.mincost_maxflow(ss,tt);        printf("Case %d: ",cas++);        if(g.flow==cnt)            write(sum),putchar('\n');        else            puts("impossible");    }    return 0;}


0 0
原创粉丝点击