poj 3801 Crazy Circuits (有源汇有上下界的最小流)

本文介绍了一个电路板上电流分配的问题,旨在找到使所有组件都能正常工作的最小总电流。通过构建有源汇及上下界的最小流模型,利用ISAP算法进行求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Crazy Circuits
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 716 Accepted: 598

Description

You’ve just built a circuit board for your new robot, and now you need to power it. Your robot circuit consists of a number of electrical components that each require a certain amount of current to operate. Every component has a + and a − lead, which are connected on the circuit board at junctions. Current flows through the component from + to − (but note that a component does not “use up” the current: everything that comes in through the + end goes out the − end). 

The junctions on the board are labeled 1, ..., N, except for two special junctions labeled + and − where the power supply terminals are connected. The + terminal only connects + leads, and the − terminal only connects − leads. All current that enters a junction from the − leads of connected components exits through connected + leads, but you are able to control how much current flows to each connected + lead at every junction (though methods for doing so are beyond the scope of this problem). Moreover, you know you have assembled the circuit in such a way that there are no feedback loops (components chained in a manner that allows current to flow in a loop). 


Figure 1: Examples of two valid circuit diagrams. In (a), all components can be powered along directed paths from the positive terminal to the negative terminal. In (b), components 4 and 6 cannot be powered, since there is no directed path from junction 4 to the negative terminal. 

In the interest of saving power, and also to ensure that your circuit does not overheat, you would like to use as little current as possible to get your robot to work. What is the smallest amount of current that you need to put through the + terminal (which you can imagine all necessarily leaving through the − terminal) so that every component on your robot receives its required supply of current to function?

Input

The input file will contain multiple test cases. Each test case begins with a single line containing two integers: N (0 ≤ N ≤ 50), the number of junctions not including the positive and negative terminals, and M (1 ≤ M ≤ 200), the number of components in the circuit diagram. The next M lines each contain a description of some component in the diagram. The ith component description contains three fields: pi, the positive junction to which the component is connected, ni, the negative junction to which the component is connected, and an integer Ii (1 ≤ Ii ≤ 100), the minimum amount of current required for component i to function. The junctions pi and ni are specified as either the character ‘+’ indicating the positive terminal, the character ‘-’ indicating the negative terminal, or an integer (between 1 and N) indicating one of the numbered junctions. No two components have the same positive junction and the same negative junction. The end-of-file is denoted by an invalid test case with N = M = 0 and should not be processed.

Output

For each input test case, your program should print out either a single integer indicating the minimum amount of current that must be supplied at the positive terminal in order to ensure that every component is powered, or the message “impossible” if there is no way to direct a sufficient amount of current to each component simultaneously.

Sample Input

6 10 
+ 1 1 
1 2 1 
1 3 2 
2 4 5 
+ - 1 
4 3 2 
3 5 5 
4 6 2 
5 - 1 
6 5 3 
4 6 
+ 1 8 
1 2 4 
1 3 5 
2 4 6 
3 - 1 
3 4 3 
0 0

Sample Output

9
impossible

Hint

For those who are electronics-inclined, imagine that you have the ability to adjust the potential on any component without altering its current requirement, or equivalently that there is an accurate variable potentiometer connected in series with each component that you can adjust. Your power supply will have ample potential for the circuit.

Source

[Submit]   [Go Back]   [Status]   [Discuss]


题目大意:一个电路板,上面有N个接线柱(标号1~N)   还有两个电源接线柱+ -
然后是 给出M个部件正负极的接线柱和最小电流
求一个可以让所有部件正常工作的总电流  没有则输出impossible

题解:有源汇有上下界的最小流

我们依然按照“有源汇有上下界的可行流”的求解方法先得到一个可行流。

在跑可行流的时候因为是按照最大流跑的,所以可能多跑了一些,为了得到原图中的最小流,我们应该在原图中实现退流,也就是在满足下界的情况下在“自由流量”中退掉尽量多的流量。方法是删除附加源汇,也就是把它们相连的那些边正向边和反向边流量都赋值为0;然后再删除那条成环的边,这样就还原了原图的自由流量构成的网络。我们从TT开始顺着反向边跑最大流,因为跑反向边等于退流,跑最大流就是退掉了尽量多的流,所以用一开始求出的可行流减去这一次求出的最大流就是答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 2003
#define inf 1000000000
using namespace std;
int n,m,tot;
int point[N],v[N],next[N],remain[N],last[N],cur[N],deep[N],num[N];
int in[N],out[N],sum[N],cal[N];
void add(int x,int y,int  z)
{
	tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
	tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
	//cout<<x<<" "<<y<<" "<<z<<endl; 
}
int addflow(int s,int t)
{
	int now=t; int ans=inf;
	while (now!=s) {
		ans=min(ans,remain[last[now]]);
		now=v[last[now]^1];
	}
	now=t;
	while (now!=s) {
		remain[last[now]]-=ans;
		remain[last[now]^1]+=ans;
		now=v[last[now]^1];
	}
	return ans;
}
void bfs(int s,int t)
{
	for (int i=1;i<=n+4;i++) deep[i]=t;
	queue<int> p; p.push(t); deep[t]=0;
	while (!p.empty()){
		int now=p.front(); p.pop();
		for (int i=point[now];i!=-1;i=next[i])
		 if (deep[v[i]]==t&&remain[i^1]) 
		  deep[v[i]]=deep[now]+1,p.push(v[i]);
	}
}
int isap(int s,int t)
{
	int now=s; int ans=0; bfs(s,t);
	for (int i=1;i<=n+4;i++) num[deep[i]]++;
	for (int i=1;i<=n+4;i++) cur[i]=point[i];
	while (deep[s]<n+4) {
		if (now==t) {
			ans+=addflow(s,t);
			now=s;
		}
		bool pd=false;
		for (int i=cur[now];i!=-1;i=next[i])
		 if (remain[i]&&deep[now]==deep[v[i]]+1){
		 	last[v[i]]=i;
		 	cur[now]=i;
		 	now=v[i];
		 	pd=true;
		 	break;
		 }
		if (!pd) {
			int minn=n+4;
			for (int i=point[now];i!=-1;i=next[i])
			 if (remain[i]) minn=min(minn,deep[v[i]]);
			if (!--num[deep[now]]) break;
			deep[now]=minn+1;
			num[deep[now]]++;
			cur[now]=point[now];
			if (now!=s) now=v[last[now]^1];
		}
	}
	return ans;
}
int calc(char s[])
{
	int num=0;
	if (s[1]=='+') return 1;
	if (s[1]=='-') return n+2;
	int len=strlen(s+1);
	for (int i=1;i<=len;i++) num=num*10+s[i]-'0';
	return num+1;
}
void init()
{
	tot=-1;
	memset(point,-1,sizeof(point));
	memset(num,0,sizeof(num));
	memset(remain,0,sizeof(remain));
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
}
bool check()
{
	for(int i=1;i<=n+2;i++)
	 if (abs(sum[i])!=remain[cal[i]]) return false;
	return true;
}
int main()
{
	freopen("a.in","r",stdin);
	//freopen("my.out","w",stdout);
	while (true) {
		scanf("%d%d",&n,&m);
		if (!n&&!m) break;
		init();
		for (int i=1;i<=m;i++) {
			char s[10],s1[10];
			int x,y,li;
			scanf("%s%s%d",s+1,s1+1,&li);
			x=calc(s); y=calc(s1);
		    //cout<<x<<" "<<y<<" "<<li<<endl;
			add(x,y,inf-li);
			in[y]+=li; out[x]+=li;
		}
		int ss=n+3; int tt=ss+1;
		for (int i=1;i<=n+2;i++){
			sum[i]=out[i]-in[i];
			if (sum[i]>0) add(i,tt,sum[i]);
			else add(ss,i,-sum[i]);
			cal[i]=tot;
		}
		add(n+2,1,inf); int ki=tot;
		int sum1=isap(ss,tt);
		if (!check()) {
			printf("impossible\n");
			continue;
		}
		remain[ki]=0; remain[ki^1]=0;
		for (int i=1;i<=n+2;i++)
		 remain[cal[i]]=0,remain[cal[i]^1]=0;
		int sum2=isap(n+2,1);
		printf("%d\n",sum1-sum2);
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值