hdu 4309 Seikimatsu Occult Tonneru(枚举+最大流)

题意:有n个城市,m条大桥,桥有三种,第一种可以让人在桥中避难,通过无限制,第二种只能让人通过,通过无限制,第三种只能让一个人通过,但是如果花费w的钱修桥,这个桥就和第二种一样了。现在要令尽量多的人在第一种桥中避难,问最多的人和最少花费。

思路:这题之前尝试了几次,但是不会做。今天读的时候才发现第三种桥最多只有12个。。。这样就好做了,枚举下修桥的状态,然后跑最大流就行了,晕。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100+10;
const int maxm=10000+10;
struct Edge
{
    int to,cap,flow,next;
    Edge(){}
    Edge(int to,int cap,int flow,int next):to(to),cap(cap),flow(flow),next(next){}
};
struct Dinic
{
    int head[maxn],cur[maxn],d[maxn],nEdge,S,T,n;
    Edge edges[maxm<<1];
    queue<int>q;
    void Init(int S,int T,int n)
    {
        memset(head,0xff,sizeof(head));
        nEdge=-1;
        this->S=S;this->T=T;
        this->n=n;
    }
    void AddEdges(int from,int to,int cap)
    {
        edges[++nEdge]=Edge(to,cap,0,head[from]);
        head[from]=nEdge;
        edges[++nEdge]=Edge(from,0,0,head[to]);
        head[to]=nEdge;
    }
    bool BFS()
    {
        memset(d,0xff,sizeof(d));
        d[S]=0;
        q.push(S);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int k=head[u];k!=-1;k=edges[k].next)
            {
                Edge e=edges[k];
                if(d[e.to]==-1&&e.cap>e.flow)
                {
                    d[e.to]=d[u]+1;
                    q.push(e.to);
                }
            }
        }
        return d[T]!=-1;
    }
    int DFS(int u,int a)
    {
        if(u==T||a==0) return a;
        int flow=0,f;
        for(int &k=cur[u];k!=-1;k=edges[k].next)
        {
            Edge e=edges[k];
            if(d[e.to]==d[u]+1&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
            {
                edges[k].flow+=f;
                edges[k^1].flow-=f;
                flow+=f;a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }
    int MaxFlow()
    {
        int flow=0;
        while(BFS())
        {
            for(int i=0;i<=n;++i) cur[i]=head[i];
            flow+=DFS(S,inf);
        }
        return flow;
    }
    void clearflow()
    {
        for(int i=0;i<=nEdge;++i)
            edges[i].flow=0;
    }
}dinic;
int ancient[15],cost[15],cnt;
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int u,v,w,p,S=0,T=n+1;
        dinic.Init(S,T,n+1);
        cnt=0;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&w);
            dinic.AddEdges(S,i,w);
        }
        for(int i=0;i<m;++i)
        {
            scanf("%d%d%d%d",&u,&v,&w,&p);
            if(p<0)
            {
                dinic.AddEdges(u,v,inf);
                dinic.AddEdges(u,T,w);
            }
            else if(p==0)
                dinic.AddEdges(u,v,inf);
            else
            {
                dinic.AddEdges(u,v,1);
                ancient[cnt]=dinic.nEdge-1;
                cost[cnt++]=w;
            }
        }
        int maxv=0,mincost=inf,N=(1<<cnt),tmp,flow;
        for(int i=0;i<N;++i)
        {
            tmp=0;
            for(int j=0;j<cnt;++j)
            {
                if(i&(1<<j))
                {
                    tmp+=cost[j];
                    dinic.edges[ancient[j]].cap=inf;
                }
                else dinic.edges[ancient[j]].cap=1;
            }
            dinic.clearflow();
            flow=dinic.MaxFlow();
            if(flow>maxv)
            {
                maxv=flow;
                mincost=tmp;
            }
            else if(flow==maxv)
                mincost=min(mincost,tmp);
        }
        if(maxv==0) printf("Poor Heaven Empire\n");
        else printf("%d %d\n",maxv,mincost);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值