P2752 [USACO4.3]街道赛跑Street Race(搜索)

这题也A了好久啊……(可能是我太菜了

看到这道题第一眼是懵的,但发现数据范围很小,稍微放轻松一些

第一题比较好解

首先我萌可以将必经之路这样理解:如果从起点到达终点必须经过它,辣么如果删掉这个点,这个图就不连通了!

因此我萌枚举每个点 进行bfs(对于点的删除处理方法很多,这里窝的方法是在bfs前就把该点的vis设为true,酱紫似乎很好写呢,也不会浪费时间复杂度)

----------------------------------------------------第一问完成分割线----------------------------------------------------------

看到第二题的第一反应就是符合条件的这些点必定都符合第一问!!

也没仔细想怎么证明就直接准备开始瞎搞了(毕竟这是一道 省选+/noi- 准备随便玩玩的。。。(泥萌可不能学我否则会和我一样刷题效率低的要死

然而谢天谢地我的rp终于回来了!!这个想法是对的

后来大概想了一下证明。符合第一问的点必定符合作为起点/终点的条件很好证明。必经了嘛。。所以肯定都能到。至于其他的点为什么不行。。。我也不太说得清楚啊!!(逃

但是!!但是!!坑点来了。终点不通往任何路口。第一遍54分就是坑在这个点QAQ(不过这个严格上说也不算坑点其实就是蒟蒻没有好好审题。。。。

那么如何保证没有公共点和公共边呢?有了前一问的基础,这题的解法就比较显然了。若图能被改点分成不连通的两个部分即为所求。

这段代码写的比较恶心。。。。详见注释

还有一个巨大的坑点!!这玩意儿可以有路通向自己!!最后一个点!!!(当然还有自环。)介个感觉题目里并没有说啊。。还是我眼瞎。。?

#include<bits/stdc++.h>
using namespace std;

int n;
bool can[60][60];
vector<int> edge[60];

bool vis[60];
bool before[60][60];//before[i][j]=true表示从起点到达终点的路径中i在j的前面 且该数组仅更新j为毕竟点的情况 详细用途见后

bool ok(int node) {
	queue<int> q;//数组和队列勿忘初始化 要不然会出大事。。
	memset(vis,false,sizeof(vis));
	vis[0]=vis[node]=true;//先设为true这样bfs时就不会从这个点走
	before[0][node]=before[node][node]=true;//其实此处before数组可以完全替代vis
	q.push(0);
	while(!q.empty()){
		int cur=q.front();
		if (cur==n-1) return true;//即图仍连通
		vis[cur]=true;
		before[cur][node]=true;
		q.pop();
		for (int i=0;i<edge[cur].size();i++) if (!vis[edge[cur][i]]) q.push(edge[cur][i]);
	}
	return false;
}

bool check(int node){//注意这个check就是当成无向图来处理了
	int nn=n;
	for (int i=0;i<edge[node].size();i++) if (before[edge[node][i]][node]) return false;//检查作为终点是该点是否通向其他点
	for (int i=0;i<n;i++) {//这段代码比较恶心了。处理点node将图分为两个时边的情况。显然从起点到终点的路径上比必经点先经过的点仍能与该点相连,而其他的点则只能与新“分裂”出的点相连(nn)
	    if (can[node][i]&&!before[i][node]) {//这里就是before函数的主要用途了。可以对照样图 理解起来并不困难
		    can[nn][i]=can[i][nn]=true;
		    can[node][i]=can[i][node]=false;
	    }
	}
	queue<int> q;
	memset(vis,false,sizeof(vis));
	q.push(0);
	while(!q.empty()){//bfs基本和先前类似
		int cur=q.front();
		if (cur==n-1) {
			for (int i=0;i<n;i++) if (can[nn][i]){//数组一定要还原!!下面也是
				can[nn][i]=can[i][nn]=false;
				can[node][i]=can[i][node]=true;
			}
			return false;
		}
		q.pop();
		if (vis[cur]) continue;
		vis[cur]=true;
		for (int i=0;i<=n;i++) if (!vis[i]&&can[cur][i]) q.push(i);
	}
	for (int i=0;i<n;i++) if (can[nn][i]) {
		can[nn][i]=can[i][nn]=false;
		can[node][i]=can[i][node]=true;
	}
	return true;
}

int main(){
	while (1){//输入
		bool flag=false;
		while(1){
			int x;
			cin>>x;
			if (x==-1) {
				flag=true;
				break;
			}
			if (x==-2) break;
			if (x!=n) edge[n].push_back(x),can[n][x]=can[x][n]=true;
		}
		if (flag) break;
		n++;
	}
	vector<int> ans;
	for (int i=1;i<n-1;i++) if (!ok(i)) ans.push_back(i);
	if(ans.size()) cout<<ans.size()<<" ";//坑点 不然两个0输出会在一行
	else cout<<0<<endl;
	vector<int> ans1;
	for (int i=0;i<ans.size();i++) {
		if (i==ans.size()-1) cout<<ans[i]<<endl;
		else cout<<ans[i]<<" ";
		if (check(ans[i])) ans1.push_back(ans[i]);
	}
	if (ans1.size()) cout<<ans1.size()<<" ";
	else cout<<0<<endl;
	for (int i=0;i<ans1.size();i++) {
		if (i==ans1.size()-1) cout<<ans1[i]<<endl;
		else cout<<ans1[i]<<" ";
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42158832/article/details/80899853