hdu 4309

来源:互联网 发布:大麦盒子dm1001网络锁 编辑:程序博客网 时间:2024/06/04 01:26

Seikimatsu Occult Tonneru

Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)


Problem Description
During the world war, to avoid the upcoming Carpet-bombing from The Third Reich, people in Heaven Empire went to Great Tunnels for sheltering.
There are N cities in Heaven Empire, where people live, with 3 kinds of directed edges connected with each other. The 1st kind of edges is one of Great Tunnels( no more than 20 tunnels) where a certain number of people can hide here; people can also go through one tunnel from one city to another. The 2nd kind of edges is the so-called Modern Road, which can only let people go through. The 3rd kind of edges is called Ancient Bridge and all the edges of this kind have different names from others, each of which is named with one of the twelve constellations( such as Libra, Leo and so on); as they were build so long time ago, they can be easily damaged by one person's pass. Well, for each bridge, you can spend a certain deal of money to fix it. Once repaired, the 3rd kind of edges can let people pass without any limitation, namely, you can use one bridge to transport countless people. As for the former two kinds of edges, people can initially go through them without any limitation.
We want to shelter the most people with the least money.
Now please tell me the largest number of people who can hide in the Tunnels and the least money we need to spend to realize our objective.
 

Input
Multiple Cases.
The first line, two integers: N (N<=100), m (m<=1000). They stands for the number of cities and edges.
The next line, N integers, which represent the number of people in the N cities.
Then m lines, four intergers each: u, v, w, p (1<=u, v<=N, 0<=w<=50). A directed edge u to v, with p indicating the type of the edge: if it is a Tunnel then p < 0 and w means the maximum number people who can hide in the the tunnel; if p == 0 then it is a Modern Road with w means nothing; otherwise it is an Ancient Bridge with w representing the cost of fixing the bridge. We promise there are no more than one edge from u to v.
 

Output
If nobody can hide in the Tunnels, print “Poor Heaven Empire”, else print two integers: maximum number and minimum cost.
 

Sample Input
4 42 1 1 01 2 0 01 3 0 02 4 1 -13 4 3 -14 42 1 1 01 2 0 01 3 3 12 4 1 -13 4 3 -1
 

Sample Output
4 04 3
 

解题思路:这道题是用网络流求解,它与一般的网络流又稍稍有些变化,由于题目中桥需要修建才能通过无限多的人,所以这里需要想办法。。桥的数目最多只有12,一般人的感觉肯定是用状态压缩,事实上确实是用状态压缩。。最开始都不修建桥,看是否能够通过全部的人,如果不行就要枚举桥,最多枚举2^12次。其实一开始我怀疑是不是会超时,事实上还是不会。。。这里最关键的是汇点的处理。。可以虚拟出一个点,如u->v的隧道,可以虚拟一个点x,连接u->x,x->v的流量无穷的边,和x->T的流量为隧道人数上限的边,这样做的目的是在流入汇点前限流。。。我之前想的是u->v的隧道建隧道人数的边,v->T建立无穷大的边,结果WA,我也没有想清楚原因,我感觉这样子也能够限流啊。。。
PS:我刚刚想到了为什么不能够按照我之前的v->T建立无穷大的边了,如果存在某一点u',u‘->v这一条边是路,容量肯定是无穷大,那么这一条边肯定把其它要修建的桥都忽略了,可以直接从这条u'->v->T,这样一来答案就会是无穷大。。。看来从源点出发的边以及到汇点的边不能够轻易地就设定为无穷大,还是要多多分析题意。。今天又学到一招-----构建虚拟点

AC:
#include <cstdio>#include <cstring>const int MAXN = 205;const int MAXM = 2505;const int INF = 1000000000;struct Edge{    int u, v, next, flow;}edge[MAXM], redge[MAXM];int edgeNumber, head[MAXN], rhead[MAXN];int source = MAXN - 1;int destination = MAXN - 2;int depth[MAXN];inline int min(int x, int y){    return x < y ? x : y;}void addEdgeSub(int u, int v, int flow){    edge[edgeNumber].u = u;    edge[edgeNumber].v = v;    edge[edgeNumber].flow = flow;    edge[edgeNumber].next = head[u];    head[u] = edgeNumber ++;}void addEdge(int u, int v, int flow){    addEdgeSub(u, v, flow);    addEdgeSub(v, u, 0);}int n, m;int bridgePosition[MAXN];int bridgeCost[MAXN];int bridgeNumber;bool bfs(int start, int end){    int front = 0, rear = 0;    int queue[MAXN];    memset(depth, -1, sizeof(depth));    queue[front++] = start;    depth[start] = 0;    while(rear < front)    {        int k = queue[rear++];        for(int i=head[k];i!=-1;i=edge[i].next)        {            int to = edge[i].v;            if(-1 == depth[to] && edge[i].flow > 0)            {                depth[to] = depth[k] + 1;                queue[front++] = to;            }        }    }    return -1 != depth[end];}int dinic(int start, int end, int sum){    if(start == end)    {        return sum;    }    int temp = sum;    for(int i=head[start];i!=-1 && sum;i=edge[i].next)    {        if(edge[i].flow > 0 && depth[edge[i].v] == depth[start] + 1)        {            int a = dinic(edge[i].v, end, min(sum, edge[i].flow));            edge[i].flow -= a;            edge[i^1].flow += a;            sum -= a;        }    }    return temp - sum;}int maxFlow(int start, int end){    int result = 0;    while(bfs(start, end))    {        result += dinic(start, end, INF);    }    return result;}int main(){    int u, v, w, p;    while(~scanf("%d%d", &n, &m))    {        int pointNumber = n + 1;        edgeNumber = 0;        bridgeNumber = 0;        memset(head, -1, sizeof(head));        for(int i=1;i<=n;++i)        {            scanf("%d", &w);            addEdge(source, i, w);        }        for(int i=0;i<m;++i)        {            scanf("%d%d%d%d",&u,&v,&w,&p);            if(p < 0)            {                addEdge(u, pointNumber, INF);                addEdge(pointNumber, v, INF);                addEdge(pointNumber, destination, w);                ++ pointNumber;            }            else if(p == 0)            {                addEdge(u, v, INF);            }            else            {                bridgePosition[bridgeNumber] = edgeNumber;                bridgeCost[bridgeNumber] = w;                addEdge(u, v, 1);                ++ bridgeNumber;            }        }        memcpy(redge, edge, sizeof(redge));        memcpy(rhead, head, sizeof(rhead));        int minCost = INF, maxPeople = - INF;        for(int i=0;i<(1<<bridgeNumber);++i)        {            memcpy(edge, redge, sizeof(edge));            memcpy(head, rhead, sizeof(head));            int cost = 0;            for(int j=0;j<bridgeNumber;++j)            {                if(i&(1 << j))                {                    cost += bridgeCost[j];                    edge[bridgePosition[j]].flow = INF;                }            }            int people = maxFlow(source, destination);            if(people > maxPeople)            {                maxPeople = people;                minCost = cost;            }            else if(people == maxPeople)            {                minCost = min(minCost, cost);            }        }        if(maxPeople > 0)        {            printf("%d %d\n", maxPeople, minCost);        }        else        {            printf("Poor Heaven Empire\n");        }    }    return 0;}


0 0
原创粉丝点击