这题也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]<<" ";
}
}