zoukankan      html  css  js  c++  java
  • nyoj677 谍战


    本题能够说是最小割入门级题目。


    假设能想到是最小割问题。那么建图思路便是水到渠成的事了。


    加入一个源点S和汇点T;

    把S与每一个间谍相连。容量为无穷大;

    把城市N(即飞机场的位置)与汇点T相连。容量为无穷大;

    之间有道路的城市相连。容量为1,注意这里是双向的边;


    建图完后,依据最大流最小割定理。那么直接求最大流就可以。


    闲话少说,上代码:

    #include<iostream>
    using namespace std;
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<queue>
    #include<stack>
    #include<map>
    #include<vector>
    #include<algorithm>
    
    #define INS 1<<30
    #define CLR(arr,v) memset(arr,v,sizeof(arr))
    
    #define MaxV 3000
    #define MaxE 100000
    
    class MaxFlow{
    public:
    	void Clear(){
    		CLR(h,-1); CLR(cnt,0); CLR(vis,0);
    		flag = false;
    		pos = top = head = total = maxflow = 0;
    	}
    	void add(int u,int v,int flow){
    		num[pos] = v;
    		sur[pos] = flow;
    		next[pos] = h[u];
    		h[u] = pos++;
    
    		num[pos] = u;
    		sur[pos] = 0;
    		next[pos] = h[v];
    		h[v] = pos++;
    	}
    	int GetMaxFlow(int s,int t){
    		init(t);
    		stk[top] = s;
    		while(!flag){
    			minres = INS;
    			if(top < 0) top = 0;
    			if(!dfs(stk[top],-1,t,minres)) continue;
    			maxflow += minres;
    			while(dis != -1){
    				sur[dis] -= minres;
    				sur[dis^1] += minres;
    				dis = pre_e[dis];
    			}
    			top = 0;
    		}
    		return maxflow;
    	}
    private:
    	int h[MaxV],num[MaxE],sur[MaxE],next[MaxE],gap[MaxV],cnt[MaxV],pre_e[MaxE],stk[MaxV],que[MaxV];
    	int pos,top,head,total,maxflow,minres,dis;
    	bool vis[MaxV],flag;
    	void init(int n){
    		que[total++] = n;
    		vis[n] = true;
    		while(head < total){
    			int p = que[head++];
    			if(head >= MaxV) head -= MaxV;
    			for(int i = h[p]; i != -1 ;i = next[i]){
    				if(!vis[ num[i] ]){
    					vis[ num[i] ] = true;
    					gap[ num[i] ] = gap[p] + 1;
    					cnt[ gap[ num[i] ] ]++;
    					que[total++] = num[i];
    					if(total >= MaxV) total -= MaxV;
    				}
    			}
    		}
    	}
    	bool dfs(int p,int father,int n,int &minres){
    		int m = minres;
    		for(int i = h[p]; i != -1 ;i = next[i]){
    			if(sur[i] > 0 && gap[p] - gap[ num[i] ] == 1){
    				minres = min(minres,sur[i]);
    				pre_e[i] = father;
    				if(num[i] != n) stk[++top] = num[i];
    				if(num[i] == n || dfs(num[i],i,n,minres)) {
    					if(num[i] == n) dis = i;
    					return true;
    				}
    				minres = m;
    			}
    		}
    		cnt[ gap[p] ]--;
    		cnt[ gap[p] + 1]++;
    		top--;
    		if(cnt[ gap[p] ] == 0) flag = true;
    		gap[p] += 1;
    		return false;
    	}
    }T;
    
    
    int main()
    {   
        int t;
        scanf("%d",&t);
        int cnt = 0;
        while (t--)
              {
              int n,m,p;
              scanf("%d%d%d",&n,&m,&p);
              
              int N = n + 1;
              T.Clear();
              
              int x;
              for (int i = 1; i <= p; ++ i)
                   scanf("%d",&x),T.add(0,x,INS);
              
              for (int i = 1; i <= m; ++ i)
                  {
                  int u,v;
                  scanf("%d%d",&u,&v);     
                  T.add(u,v,1);
                  T.add(v,u,1);
                  }
              
              T.add(n,N,INS);
        
              printf("Case #%d: %d
    ",++cnt,T.GetMaxFlow(0,N));
              }
        return 0;
    }
    



  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7252738.html
Copyright © 2011-2022 走看看