POJ-1087-A Plug for UNIX

378 篇文章 0 订阅
这个题是说在一个会议室里有n种插座,每种插座一个,每个插座只能插一种以及一个电器或者购买适配器使得其他接口的设备可以用。有m个设备,每个设备需要接到指定的插座上,并非所有的设备都可以插到插座上。有k中适配器可以选择(数量无限),eg适配器(a,b) 表示可以把b类插座变为a类插座,让你求出至少有多少个设备无法使用。

思路:
1、不难想到这个题应该用最大流做,最后总的设备数减最大流即为所求答案。

2、建图的时候将源点与对应插座编号(自己编号)相连,权值为当前插座个数。

3、将对应插座与汇点相连,权值为对应的设备数量。

4、将适配器对应相连,权值为无穷大。

5、跑最大流即可,我用的Dinic

注意:

1、设备所需的插座可能存在前面没有提供的情况,需考虑加边。

2、适配器可能2边转换都在设备需要插座与插座都没出现过,但它可以起到中转的作用,所以适配器的时候每个都要考虑加新边的情况

3、题目中点说是100,但实际好像是500+,边数要计算好

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=600;
const int maxm=30000;
const int inf=1<<29;
int n,m,k,e,st,des,num,head[maxn],pnt[maxm],nxt[maxm],flow[maxm],level[maxn],q[maxn],cnta[maxn],cntb[maxn];
char str[maxn][30];
void AddEdge(int u,int v,int c)
{
    pnt[e]=v;nxt[e]=head[u];flow[e]=c;head[u]=e++;
    pnt[e]=u;nxt[e]=head[v];flow[e]=0;head[v]=e++;
}
bool BFS()
{
    memset(level,0,sizeof(level));
    level[st]=1;
    int pre=0,last=0;
    q[last++]=st;
    while(pre<last)
    {
	if(q[pre]==des)
	    return true;
	for(int i=head[q[pre]];i!=-1;i=nxt[i])
	    if(flow[i]&&!level[pnt[i]])
	    {
		level[pnt[i]]=level[q[pre]]+1;
		q[last++]=pnt[i];
	    }
	pre++;
    }
    return false;
}
int DFS(int u,int sum)
{
    if(u==des)
	return sum;
    for(int i=head[u],t;i!=-1;i=nxt[i])
	if(flow[i]&&level[pnt[i]]==level[u]+1&&(t=DFS(pnt[i],min(sum,flow[i]))))
	{
	    flow[i]-=t;
	    flow[i^1]+=t;
	    return t;
	}
    return level[u]=0;
}
int maxflow()
{
    int ans=0;
    while(BFS())
	while(1)
	{
	    int val=DFS(st,inf);
	    if(!val)
		break;
	    ans+=val;
	}
    return ans;
}
int GetNum(char *name)
{
    for(int i=1;i<num;i++)
	if(!strcmp(str[i],name))
	    return i;
    return -1;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
	e=0,num=1;
	memset(head,-1,sizeof(head));
	memset(cnta,0,sizeof(cnta));
	memset(cntb,0,sizeof(cntb));
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
	    scanf("%s",str[num]);
	    int index=GetNum(str[num]);
	    if(index==-1)
		cnta[num++]++;
	    else
		cnta[index]++;
	}
	scanf("%d",&m);
	char a[101],b[30];
	for(int i=0;i<m;i++)
	{
	    scanf("%s%s",a,b);
	    int index=GetNum(b);
	    if(index==-1)
	    {
		strcpy(str[num],b);
		cntb[num++]++;
	    }
	    else
		cntb[index]++;
	}
	st=0,des=num++;
	for(int i=1;i<num;i++)
	{
	    if(cnta[i])
		AddEdge(i,des,cnta[i]);
	    if(cntb[i])
		AddEdge(st,i,cntb[i]);
	}
	scanf("%d",&k);
	for(int i=0;i<k;i++)
	{
	    scanf("%s%s",a,b);
	    int numa=GetNum(a);
	    int numb=GetNum(b);
	    if(numa==-1)
	    {
		strcpy(str[num],a);
		numa=num++;
	    }
	    if(numb==-1)
	    {
		strcpy(str[num],b);
		numb=num++;
	    }
	    AddEdge(numa,numb,inf);
	}
	printf("%d\n",m-maxflow());
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值