【HDOJ】2242 考研路茫茫——空调教室(找边双连通分量+dfs+注意重边的处理)


http://192.168.102.19/showproblem.php?pid=2242

分析

1.首先,这是一张无向图。如果图中不存在桥,也就是无论去掉哪条边都不能把原图(联通)分为两个不联通的图,那么输出impossible(具体可以用tarjan算法找图中的桥
2.如果原图是张DAG图,那么可以通过dfs求出最小的答案。但是图中可能存在环,所以我们首先要进行缩点。这里的缩点也是用tarjan算法(依据无向图的性质,这里的tarjan是针对边双连通分量的),可以就做一遍tarjan
3.对缩点后的整张图进行dfs,得出答案

特别要注意这里可能存在重边的情况,我在这里给出了判断的方法和我认为的原因qwq
细节见代码

code

#include    
#define ll long long      
using namespace std;
const int N = 10005,M = 200005;
int n,m;
vectorg[N],v[N];
bool in[N],vis[N];
int cnt,t,sum,bridge;
int dfn[N],low[N],sta[N],a[N],va[N],f[N];
int x[M],y[M];
int dp[N];
int ans;

void init(){
	cnt=t=sum=0;
	bridge=0;
	ans=1e9;
	for(int i=1;i<=n;i++){
		dfn[i]=low[i]=sta[i]=va[i]=f[i]=dp[i]=0;
		vis[i]=in[i]=0;
		g[i].clear();
		v[i].clear(); 
	}
}

void tarjan(int now,int fa){  
	dfn[now]=low[now]=++cnt;
	sta[++t]=now;   
	in[now]=1;
	int flag=0;	
	for(int i=0;idfn[now]){
				bridge++;
			}
		}
		else{
			if(in[x]){   //如果不在栈中,表示x和now没有父子关系 ,可以无视 
				low[now]=min(low[now],dfn[x]);
			}
		}
	}
	
	if(dfn[now]==low[now]){
		int cur;
		do{
			cur=sta[t];
			f[cur]=now;
			in[cur]=0;
			va[now]+=a[cur];
			t--;
		}while(now!=cur);
	}
} 

void dfs(int now,int fa){
	vis[now]=1;
	dp[now]=va[now];
	for(int i=0;i>n>>m){
		init();
		for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i];
		for(int i=1;i<=m;i++){
			scanf("%d%d",&x[i],&y[i]);
			x[i]+=1;
			y[i]+=1;
			g[x[i]].push_back(y[i]);
			g[y[i]].push_back(x[i]);
		}
		for(int i=1;i<=n;i++){
			if(!dfn[i]){
				tarjan(i,i);
			}
		}
		if(bridge==0){  // or cc==1(只有一个环) 
			puts("impossible");
			continue;
		}
		for(int i=1;i<=m;i++){
			if(f[x[i]]!=f[y[i]]){
				v[f[x[i]]].push_back(f[y[i]]);
				v[f[y[i]]].push_back(f[x[i]]);
			}
		}
		dfs(1,1);
		cout<