POJ 3084

来源:互联网 发布:linux复制多个文件 编辑:程序博客网 时间:2024/06/06 04:57

第一道最大流的题, 网络流的题都是图不好建立, 一般能想到怎么建图,题就过了

给你一些房间,和房间之间的关系, 

问你至少需要关几个门,才能是你想保卫的房间不受到侵犯;

样例解释:

 m->room numbers , n->the room number that you want to defence

(room numbre from 0 to m-1)

char -> the room whether have an  intruder or not   c-> the numbre of the rooms it can  go freely  xi -> the room's number

解题思路

   抽象成一个最大流问题,房间看成点, 门看成边,如果此房间有别的房间的钥匙,那么无论关上几扇门都没有作用,所以流量就是INF, 但是如果这个房间没有别的房间的钥匙,那么它与别的房间的流量就是1(在存在门的前提下,只可以通过门进入),求最大流,就是至少需要关闭的门数才能保证指定的房间不收侵犯

算法 : ISPA


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


using namespace std;
#define MAXN 20000
#define MAXM 2000002
#define INF 0x1f1f1f


struct Edge
{
    int u, v, c;
    int next;
    Edge(){};
    Edge( int tu, int tv, int tc, int tn):u(tu), v(tv), c(tc), next(tn){};
};


Edge E[MAXM * 3];
int head[MAXN], cur[MAXN], que[MAXN], cnt[MAXN],d[MAXN],low[MAXN], nE;
int vis[MAXN];
void initNetWork()
{
    memset(head, -1, sizeof(head));
    nE = 0;
}


void addEdge( int u, int v, int c, int rc = 0)//rc 反向弧流量, c正向弧流量
{
    E[nE] = Edge(u, v, c, head[u]);
    head[u] = nE++;
    E[nE] = Edge(v, u, rc, head[v]);
    head[v] = nE++;
}


int maxflow( int n, int source, int sink)
{
    //bfs 算出d[i]的最小值
    //d[i]表示每个顶点I到源点的无权最短距离(隔几个点)
    int *fr = que, *ta = que;
    for( int i = 0; i < n; i++)
      d[i] = n, cnt[i] = 0;
    cnt[0]++, d[sink] = 0;
    cnt[n] = n-1;
    *ta++ = sink;
    while( fr < ta)
    {
        int v = *fr++;
        for( int i = head[v];i != -1; i = E[i].next)
        {
            //d[E[i].v] == n 表示E[i].v没有访问过
            if(d[E[i].v] == n && E[i^1].c > 0)
            {
                d[E[i].v] = d[v] + 1;
                cnt[n]--;
                cnt[d[E[i].v]] ++;
                *ta ++ = E[i].v;
            }
        }
    }
    int u = source, top = 0, flow = 0;
     low[0] = INF;
     cnt[0] = n;
    //memcpy(cur, head, sizeof(head));
    for( int i = 0; i < n ; i++)
     cur[i] = head[i];
    while(d[source] < n)
    {
        int &i = cur[u];
        for(; i != -1; i = E[i].next)
        {
            if(E[i].c > 0 && d[u] == d[E[i].v] + 1)
            {
                low[top + 1] = low[top] < E[i].c ? low[top] : E[i].c;
                que[++top] = i;//QUE存的是边
                u = E[i].v;
                break;
            }
        }


        if(i != -1)
        {
            if( u == sink)
            {
                int delta = low[top];
                for( int p = 1,i; p <= top ;p++)
                {
                    i = que[p];
                    E[i].c -= delta;
                    E[i^1].c += delta;
                }
                flow += delta;
                low[0] = INF;
                top = 0;
                u = source;
            }
        }
        else
        {
            int old_du = d[u];
            cnt[old_du] --;
            d[u] = n -1 ;
            for( int i = head[u];  i != -1; i = E[i].next)
            {
                if(E[i].c > 0 && d[u] > d[E[i].v])
                  d[u] = d[E[i].v];
            }
            cnt[++d[u]]++;
            if(d[u] < n)
             cur[u] = head[u];
            if(u != source)
            {
                u = E[que[top]].u;
                top--;
            }
            if(cnt[old_du] == 0)
             break;
        }
    }
    return flow;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        initNetWork();
        int m,n;
        scanf("%d %d",&n, &m);
        char s[5];
        int c, u, v;
        int ss = n, tt = m;
        getchar();
        for( int i = 0; i < n; i++)
        {
            scanf("%s%d",s, &c);
             if(strcmp(s,"I") == 0)
               addEdge(ss, i, INF,1);
            while(c--)
            {
                scanf("%d",&v);
                   addEdge( i, v, INF,1);
            }
        }
        int ans = maxflow(n+1, ss, tt);
        if(ans >= INF)
         printf("PANIC ROOM BREACH\n");
        else
         printf("%d\n",ans);
    }
    return 0;
}


0 0