HDU3749 Financial Crisis

Financial Crisis

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1006    Accepted Submission(s): 329


Problem Description
Because of the financial crisis, a large number of enterprises go bankrupt. In addition to this, other enterprises, which have trade relation with the bankrup enterprises, are also faced with closing down. Owing to the market collapse, profit decline and funding chain intense, the debt-ridden entrepreneurs
have to turn to the enterprise with stably developing for help.

Nowadays, there exist a complex net of financial trade relationship between enterprises. So if one of enterprises on the same financial chain is faced with bankrupt, leading to cashflow's obstruction, the other enterprises related with it will be influenced as well. At the moment, the foresight entrepreneurs are expected the safer cooperation between enterprises. In this sense, they want to know how many financial chains between some pairs of enterprises are independent with each other. The indepence is defined that if there exist two roads which are made up of enterprises(Vertexs) and their financial trade relations(Edge) has the common start point S and end point T, and expect S and T, none of other enterprise in two chains is included in these two roads at the same time. So that if one of enterpirse bankrupt in one of road, the other will not be obstructed.

Now there are N enterprises, and have M pair of financial trade relations between them, the relations are Mutual. They need to ask about Q pairs of enterprises' safety situations. When two enterprises have two or more independent financial chains, we say they are safe enough, you needn't provide exact answers.
 

Input
The Input consists of multiple test cases. The first line of each test case contains three integers, N ( 3 <= N <= 5000 ), M ( 0 <= M <= 10000 ) and Q ( 1 <= Q <= 1000 ). which are the number of enterprises, the number of the financial trade relations and the number of queries.
The next M lines, each line contains two integers, u, v ( 0 <= u, v < N && u != v ), which means enterpirse u and enterprise v have trade relations, you can assume that the input will not has parallel edge.
The next Q lines, each line contains two integers, u, v ( 0 <= u, v < N && u != v ), which means entrepreneurs will ask you the financial safety of enterpirse u and enterprise v.
The last test case is followed by three zeros on a single line, which means the end of the input.
 

Output
For each case, output the test case number formated as sample output. Then for each query, output "zero" if there is no independent financial chains between those two enterprises, output "one" if there is only one such chains, or output "two or more".
 

Sample Input
 
 
3 1 2 0 1 0 2 1 0 4 4 2 0 1 0 2 1 2 2 3 1 2 1 3 0 0 0
 

Sample Output
 
 
Case 1: zero one Case 2: two or more one
 


题目大意:

       给你一个(保证输入无重边,无自环)无向图,然后有下面Q条询问,每条询问为:问你u点与v点之间有几条(除了首尾两点外,其他点不重复)的路径.如果有0条或1条输出“zero”或"one",如果有2条以上,输出”two or more”。

解析:

       点双连通分量。

       首先用Tarjan求出整个无向图的点双连通分量,然后对于每一个询问,有以下三种情况:

       1.两个点原本就不相连,则路径数为0,可用并查集实现。

       2.两个点在一个点数为2的点双连通分量内,则路径数为1。

       3.两个点在一个点数大于2的点双连通分量内,则路径数大于1。


代码(速度还不够优秀,需要改进):

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <ctime>
#include <queue>
#include <vector>
using namespace std;

const int Max=50010;
int n,m,q,s,size,cnt,tot,Index,root=1;
int first[Max],fa[Max];
int num[Max],low[Max],p[Max];
struct shu{int to,next;};
shu bian[Max];
vector<int>father[5005];

inline int get_int()
{
   int x=0,f=1;
   char c;
   for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
   if(c=='-') {f=-1;c=getchar();}
   for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
   return x*f;
}

inline void clean()
{
   size=1;cnt=0;
   memset(first,0,sizeof(first));
   memset(father,0,sizeof(father));
   memset(num,0,sizeof(num));
   memset(low,0,sizeof(low));
   memset(bian,0,sizeof(bian));
}

inline void build(int x,int y)
{
   size++;
   bian[size].next=first[x];
   first[x]=size;
   bian[size].to=y;
}

inline int getfather(int v)
{
   if(fa[v]==v) return v;
   fa[v]=getfather(fa[v]);
   return fa[v];
}

inline void merge(int x,int y)
{
   int i=getfather(x);
   int j=getfather(y);
   if(i!=j) fa[i]=j;
}

inline void tarjan(int point)
{
   if(point==root&&first[point]==0)
   {
   	 father[++cnt].push_back(point);
   	 return;
   }

   low[point]=num[point]=++Index;
   p[++tot]=point;
   int son=0;
   for(int u=first[point];u;u=bian[u].next)
   {
   	 if(!num[bian[u].to])
   	 {
   	   tarjan(bian[u].to);
   	   low[point]=min(low[point],low[bian[u].to]);
   	   if(num[point]<=low[bian[u].to])
   	   {
   	   	 son++;cnt++;
   	   	 int x;
		 do
		 {
		 x=p[tot--];
		 father[cnt].push_back(x);
		 }while (x!=bian[u].to);
		 father[cnt].push_back(point);
   	   }
   	 }
   	 else low[point]=min(low[point],num[bian[u].to]);
   }
}

int main()
{
   //freopen("lx.in","r",stdin);
   //freopen("lx.out","w",stdout);

   while(scanf("%d%d%d",&n,&m,&q))
   {
   	 if(n==0&&m==0&&q==0) break;
   	 s++;
   	 cout<<"Case "<<s<<":\n";
   	 clean();
   	 for(int i=1;i<=n;i++) fa[i]=i;
   	 for(int i=1;i<=m;i++)
   	 {
   	   int x=get_int(),y=get_int();x++;y++;
   	   build(x,y);
   	   build(y,x);
   	   merge(x,y);
   	 }

   	 for(int i=1;i<=n;i++)
	   if(!num[i])
	   {
	   	 root=i;
	     tarjan(i);
	   }

   	 while(q--)
   	 {
   	   int x=get_int(),y=get_int();x++;y++;
   	   if(getfather(x)!=getfather(y)) cout<<"zero\n";
   	   else
   	   {
   	   	 int flag=0;
   	   	 for(int i=1;i<=cnt;i++)
   	   	 {
   	   	   int sum=0;
   	   	   for(int j=0;j<father[i].size();j++) if(father[i][j]==x||father[i][j]==y) sum++;
   	   	   if(sum==2&&father[i].size()==2) {flag=1;cout<<"one\n";break;}
   	   	   if(sum==2&&father[i].size()>2) {flag=1;cout<<"two or more\n";break;}
   	     }
   	     if(!flag) cout<<"one\n";
   	   }
   	 }
   }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值