POJ-1087UNIX最大フロースーパーソース用プラグ

トピックリンク

https://vjudge.net/problem/POJ-1087

題名

n個のソケット、m個のプラグ、k個のコンバーター(BCは、ソケットBをソケットCに変換でき、コンバーターを積み重ねることができることを意味します)、少なくともいくつかのプラグにはプラグを差し込む場所がありません

アイデア

英語が苦手で、タイトルを読むのが痛い

最初にPOJディスカッションリンクを投稿すると、その中にいくつかのデータセットがあります
http://poj.org/showmessage?message_id=146848

少なくともいくつかのプラグを差し込む場所がない場合は、できるだけ多くのプラグを使用してください。プラグとソケットのマッチング関係を確立し、最大フローを実行します。

特定のマッピング部分は、ソースポイントがすべてのプラグに接続され、容量が1、プラグが必要なソケットに接続され、容量が1、コンバータの2つのソケットがエッジに接続され、容量がinf(双方向ではないことに注意)、すべてのソケットがシンクポイントに接続されることです。サイドキャパシティが1であっても、最大フローを実行するだけです。

ソケットが与えるものはすべて文字列です。マップを使用してマッピングを作成するだけです。

コード

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
using namespace std;

	typedef long long ll;
	const int inf=0x3f3f3f3f;
	const int maxn=10100;//开大点没坏处~~ 
	const int maxe=200010;

	int head[maxn],cnt;
	struct Edge{
    
    
		int v;
		int w;
		int next;
	}edge[maxe];

	int n,m,k,s,t;
	ll maxflow;
	int deep[maxn];
	int now[maxe];


	void init(){
    
    
		memset(head,-1,sizeof(head));
		cnt=0;
		maxflow=0; 
		return ;	
	}
	void add(int u,int v,int w){
    
    
	//	cout<<u<<" "<<v<<endl;
	//果然多刷题才能提高,注释的这句是我自己想出来用来调试的,哪出了岔子太好看出来了 
  		edge[cnt].v=v;
		edge[cnt].w=w;
		edge[cnt].next=head[u];
		head[u]=cnt++;
	}

	inline bool bfs(){
    
    
    	memset(deep,0x3f,sizeof(deep));
    	queue<int>q;
    	q.push(s);deep[s] = 0;now[s] = head[s];
    	while(q.size()){
    
    
        	int x = q.front();q.pop();
        	for(int i=head[x];i!=-1;i=edge[i].next){
    
    
        	    int y=edge[i].v;
         	    if(edge[i].w>0&&deep[y]==inf){
    
    
         	    	q.push(y);
        	        now[y]=head[y];
         	       	deep[y]=deep[x]+1;
        	        if(y==t)	return 1;
				}
        	}
    	}
    	return 0;
	}

	ll dfs(int x,int flow){
    
    
    	if(x==t)	return flow;
    	ll ans = 0,k,i;
    	for(i=now[x];i!=-1&&flow;i=edge[i].next){
    
    
        	now[x]=i;
        	int y=edge[i].v;
        	if(edge[i].w>0&&(deep[y]==deep[x]+1)){
    
    
        	    k=dfs(y,min(flow,edge[i].w));
         		if(!k)	deep[y]=inf;
            	edge[i].w-=k;
            	edge[i^1].w+=k;
            	ans+=k;
            	flow-=k;
        	}
    	}
    	return ans;
	}	

	void dinic(){
    
    
    	while(bfs())
    	    maxflow+=dfs(s,inf);
	}
	map<string,int>chazuo;//建立插座和数字的映射 
	string need[105];//见样例,comb需要X,但第一部分输入没有X,所以先存一下,处理完再建图 
	int main(){
    
    	
		IOS
		init();
		cin>>n;
		string str;
		
		s=1000,t=s+1;//查了半天错发现st写错了,下次直接写到一个根本到不了的数 
    	for(int i=1;i<=n;i++){
    
    
    		cin>>str;
    		chazuo[str]=i;//1-n是插座(酒店有的) 
		}
		cin>>m;
		for(int i=1;i<=m;i++){
    
    
			cin>>str;//名字无意义 
			cin>>need[i];
		}
		cin>>k;
		int ct=n+1;//可能出现新的插座类型,这个是建映射用的 
	    for(int i=1;i<=k;i++){
    
    
    		string s1,s2;
    		cin>>s1>>s2;
    		if(!chazuo[s1])
    			chazuo[s1]=ct++;
    		if(!chazuo[s2])
    			chazuo[s2]=ct++;
    		add(chazuo[s1],chazuo[s2],inf);//转换器数目无限,inf 
    		add(chazuo[s2],chazuo[s1],0);
		}
		for(int i=1;i<=m;i++){
    
    
			add(i+n+100,chazuo[need[i]],1);//因为总插座不一定只有n个,我们将插头从n+100+1开始编号 
			add(chazuo[need[i]],i+n+100,0);
		}
		for(int i=1;i<=m;i++)
			add(s,i+100+n,1),add(i+100+n,s,0);//源点向插头连边 
		for(int i=1;i<=n;i++)
			add(i,t,1),add(t,i,0);//插座向汇点连边 
			
    	dinic();
    	cout<<m-maxflow<<endl; 
    	return 0;
	}

おすすめ

転載: blog.csdn.net/TheSunspot/article/details/108151698