河南省第十一届acm G- Checkpoints

 
 

As a landlocked country in central and southern Africa , the political situation has been relatively stable since the implementation of multi-party elections in ZBA in 1991. But the ZBA parliament passed the 90 day emergency order issued by the president on 11 days of local time . The tension is that the patriotic team led by the government troops and NPG leaders founded by aborigines started, in addition to the unlawful insurgents of illegal militants.

 

Chinese peacekeepers  are going to the town of Kerver to seek Chinese foreign aid engineers.

The military map shows that there are many checkpoints in the war zone. It can be modeled as a directed graph:  nodes represent checkpoints , and edges represents the roads. The goal is that the less peacekeepers  pass the checkpoints,  the safer it will be.

输入

 
 

The first line of the input contains one integer T, which is the number of  test cases (1<=T<=5).  Each test case specifies:

     * Line 1:      N  M  A  B          (2 ≤ N ≤ 100)

N and M  denote the number of nodes and edges in the directed graph respectively. The checkpoints  are labeled 1, 2, ..., N,  where chinese peacekeepers at node A and foreign aid engineers at node B.  

  *Line 2~m+1:  Xi  Yi   (i=1, …., M)

followed by M  lines containing two integers Xi and Yi  (1 ≤ Xi, Yi ≤ N), denoting that there is a directed edge from node Xi to node Yi in the network. 

输出

 
 

For each test case generate a single line:  a single integer that  the minimum number of checkpoints . If a checkpoint is passed on the way back and forth , it will be counted only once. 

样例输入

复制
1
6  10  
1  5
1  2
2  1
2  3
3  5
5  4
4  2
1  6
6  5
5  3
3  2

样例输出

复制
2

#include <bits/stdc++.h> 
using namespace std;  
const int maxn=110;  
int n,m,a,b; //点数,边数  
int dfs_clock;//时钟  
int scc_cnt;//强连通分量总数  
vector<int> G[maxn];//G[i]表示i节点指向的所有点  
//int ss[maxn];记录G[i]是否该删除 
int pre[maxn]; //时间戳  
int low[maxn]; //u以及u的子孙能到达的祖先pre值  
int sccno[maxn];//sccno[i]==j表示i节点属于j连通分量  
//int gg[maxn];记录原来得sccno 
int ji[maxn];
int mmin;
stack<int> S;  
void dfs(int u)  
{  
    pre[u]=low[u]=++dfs_clock;  
    S.push(u);  
    for(int i=0;i<G[u].size();i++)  
    {  
        int v=G[u][i];  
        if(!pre[v])  
        {  
            dfs(v);  
            low[u]=min(low[u],low[v]);  
        }  
        else if(!sccno[v])  
        {  
            low[u]=min(low[u],pre[v]);  
        }  
    }  
    if(low[u] == pre[u])//u为当前强连通分量的入口  
    {  
        scc_cnt++;  
        while(true)  
        {  
            int x=S.top(); S.pop();  
            sccno[x]=scc_cnt;  
            if(x==u) break;  
        }  
    }  
}  
//求出有向图所有连通分量  
void find_scc(int n)  
{  
    scc_cnt=dfs_clock=0;  
    memset(sccno,0,sizeof(sccno));  
    memset(pre,0,sizeof(pre));  
    for(int i=1;i<=n;i++)  
        if(!pre[i]) dfs(i);  
}  
void kao(int wf[110],int s){
	int gg[110];
	int we[110];
	int ss[110];
	for(int i=1;i<=n;i++)
		we[i]=wf[i];
	/*
	printf("/**** %d *****\\\n",s);
	for(int i=1;i<=n;i++)  
            printf("%d号点属于%d分量\n",i,we[i]); 
			*/
    for(int i=1;i<=n;i++){
        //printf("%d %d %d %d\n",we[a],we[i],i,s);
        if(i==b || i==a || ji[i]){
        	continue;
		}
		else if(we[a]==we[i]){
			int ww=G[i].size();
				for(int j=0;j<ww;j++){
				ss[j]=G[i][j];
				}
			G[i].clear();  
			find_scc(n); 
			for(int j=1;j<=n;j++)
				gg[j]=sccno[j];
			if(gg[a]==gg[b]){
				//printf("%d**\n",i);
				int sum=0;
				for(int j=1;j<=n;j++)
        		if(gg[a]==gg[j]){
        			sum++;
				}
				mmin=min(mmin,sum);
				ji[i]=1;
				kao(gg,s+1);
				/*
				printf("/** %d **\\\n",s);
				for(int i=1;i<=n;i++)  
            		printf("%d号点属于%d分量\n",i,we[i]);  
            		*/
			}
			for(int j=0;j<ww;j++){
			G[i].push_back(ss[j]);
			}
		}
	}
	return;
}
int main()  
{   int t;
	scanf("%d",&t);
	while(t--){
		memset(ji,0,sizeof(ji));
		scanf("%d %d %d %d",&n,&m,&a,&b);
        for(int i=1;i<=n;i++) G[i].clear();  
        while(m--)  
        {  
            int u,v;  
            scanf("%d%d",&u,&v);  
            G[u].push_back(v);  
        }  
        find_scc(n);  
        mmin=0;
        for(int i=1;i<=n;i++)
        	if(sccno[i]==sccno[a]){
        		mmin++;
		}
		kao(sccno,1);
		printf("%d\n",mmin-2);
    }  
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值