后续如果还有补题会继续补
Puzzle: Wagiri
思路其实很直观
首先将轮边抽出来
做一遍边双(去掉桥)
然后用切边将他们练成一棵树即可
我考场上用了拓扑求环,后面发现还要处理桥
改了之后一直T
赛后把Cin改成scanf就过了?
我关同步流了呀…
又是裂开的一天
这是赛时的代码,唯一区别就是把cin改成了scanf
写的确实丑…
#include<bits/stdc++.h>
using namespace std;
const int N = 4e5+100;
typedef pair < int , int > pii;
#define fi first
#define se second
vector < int > a0[N];
vector < int > a1[N];
struct Ed{
int u,uu,v,vv;
};
vector < Ed > e[N],tr[N];
struct Node{
int y,Next;
}ee[2*N];
#define pb push_back
int fa[N];
int n,m;
int du[N];
bool ish[N];
bool vis[N];
int len = 1, Linkk[N];
int ho[N];
int dfn[N],low[N];
map < pair < int , int > , bool > Mat,bri,edg;
vector < pair < int , int > > ans;
void Insertt(int x,int y){
ee[++len] = (Node){y,Linkk[x]};
Linkk[x] = len;
}
void Add(int x,int y,int op){
// cout<<"OK";
if (op == 0){
a0[x].pb(y); a0[y].pb(x);
Insertt(x,y); Insertt(y,x);
du[x]++; du[y]++;
}
else{
// cout<<"OK";
a1[x].pb(y); a1[y].pb(x);
}
}
int sz;
int cnt;
void Dfs(int x,vector <int> &ex){
ex.pb(x);
vis[x] = 1; sz++;
for (int i = 0; i < a0[x].size(); i++){
int y = a0[x][i]; if (vis[a0[x][i]]) continue;
if (!ish[x]) continue; if (bri[{x,y}]) continue;
Dfs(y,ex);
}
}
void Top(){
queue < int > q;
for (int i = 1; i <= n; i++)
if (du[i] == 1) q.push(i);
// cout<<"OK";
while (q.size()){
// cout<<q.size()<<endl;
int x = q.front(); q.pop();
ish[x] = 0;
for (int i = 0; i < a0[x].size(); i++){
int y = a0[x][i];
du[y]--; if (du[y] == 1) q.push(y);
}
}
// cout<<"OK";
for (int i = 1; i <= n; i++) if (ish[i] == 1 && !vis[i]){
vector < int > ex; sz = 0;
Dfs(i,ex);
// cout<<"i = "<<i<<' '<<sz<<endl;
if (sz == 1) {ish[i] = 0;continue;}
int bh = ex[0]+n;
for (int j = 0; j < ex.size(); j++) ho[ex[j]] = bh;
ex.clear();
}
// for (int i = 1; i <= n;i++) if (ish[i]) cout<<i<<' '<<ho[i]<<endl;
}
void Add1(int lax,int lay,int nowx,int nowy){
e[nowx].pb({lax,nowx,lay,nowy});
e[nowy].pb({lay,nowy,lax,nowx});
}
int num[N];
int Getfa(int x){
return fa[x] == x?x:fa[x] = Getfa(fa[x]);
}
void printh(int x){
vis[x] = 1;
for (int i = 0; i < a0[x].size(); i++){
int y = a0[x][i];int x0 = x , y0 = y;
if (ho[y] != ho[x]) continue;
if (x0 > y0) swap(x0,y0);
if (!Mat[{x0,y0}]) ans.pb({x,y}),Mat[{x0,y0}] = 1;
if (!vis[y]) printh(y);
}
}
void print(int x){
if (x > n) printh(x-n);
for (int i = 0; i < tr[x].size(); i++){
Ed X = tr[x][i];
if (X.u ==X.uu && X.v == X.vv){
ans.pb({X.uu,X.vv});
print(X.vv);
continue;
}
if (X.u !=X.uu && X.v != X.vv){
ans.pb({X.u,X.v});
print(X.vv);
continue;
}
if (X.u != X.uu){
ans.pb({X.u,X.vv});
print(X.vv);
continue;
}
ans.pb({X.uu,X.v});
print(X.vv);
}
}
void Print(){
int st = 1; if (ish[st]) st = ho[st];
print(st);
printf("YES\n%d\n",ans.size());
for (int i = 0 ; i < ans.size(); i++){
int x = ans[i].first , y = ans[i].second;
if (edg[{x,y}] == 1) printf("%d %d\n",x,y);
else printf("%d %d\n",y,x);
}
return ;
}
void dfs(int x){
if (num[Getfa(x)] == cnt){
Print(); exit(0);
}
for (int i = 0; i < e[x].size(); i++){
int y = e[x][i].vv; int xx = Getfa(x) , yy = Getfa(y);
if (xx == yy) continue;
fa[yy] = xx; num[xx]+=num[yy];
tr[x].pb(e[x][i]);
dfs(y);
}
}
int ti = 0;
void Tarjan(int x,int La){
dfn[x] = low[x] = ++ti;
for (int i = Linkk[x]; i; i = ee[i].Next){
int y = ee[i].y;
if (!dfn[y]){
Tarjan(y,i);
low[x] = min(low[x],low[y]);
if (low[y] > dfn[x])
bri[{x,y}] = 1 , bri[{y,x}] = 1;
}
else if (i != (La^1))
low[x] = min(low[x],dfn[y]);
}
}
int main(){
// cin.tie(0);
// ios::sync_with_stdio(false);
scanf("%d %d",&n,&m);
memset(ish,1,sizeof ish);
for (int i = 1; i <= m; i++){
int x,y; string s; scanf("%d %d",&x,&y); cin>>s;
while (s.size() == 0) cin>>s;
// if (edg[{x,y}]) continue;
edg[{x,y}] = 1;
if (s == "Lun") Add(x,y,0);
else if (s == "Qie") Add(x,y,1);
}
for (int i = 1; i <= n; i++) if (!dfn[i]) Tarjan(i,0);
Top();
memset(vis,0,sizeof vis);
for (int i = 1; i <= n; i++){
int x = i; if (ish[i]) x = ho[i];
if (vis[x]) continue; cnt++; vis[x] = 1;
}
for (int i = 1; i <= 2*n; i++) fa[i] = i,num[i] = 1;
// cout<<"cnt = "<<cnt<<endl;
for (int i = 1; i <= n; i++){
int x = i; if (ish[i]) x = ho[i];
for (int j = 0; j < a1[i].size(); j++){
int to = a1[i][j]; int y = to; if (ish[y]) y = ho[y];
if (x == y) continue;
Add1(i,to,x,y);
}
}
memset(vis,0,sizeof vis);
int st = 1; if (ish[st]) st = ho[st];
dfs(st);
cout<<"NO";
return 0;
}
后面用边双重新写了一遍:
#include<bits/stdc++.h>
using namespace std;
const int N = 4e5+100;
typedef pair < int , int > pii;
#define fi first
#define se second
vector < int > a1[N];
struct Ed{
int u,uu,v,vv;
};
vector < Ed > e[N],tr[N];
struct Node{
int y,Next;
}ee[2*N];
#define pb push_back
int n,m;
bool ish[N];
bool vis[N];
int len = 1, Linkk[N];
int ho[N];
int dfn[N],low[N];
map < pair < int , int > , bool > Mat;
vector < pair < int , int > > ans;
void Insertt(int x,int y){
ee[++len] = (Node){y,Linkk[x]};
Linkk[x] = len;
}
void Add(int x,int y,int op){
if (op == 0){
Insertt(x,y); Insertt(y,x);
}
else{
a1[x].pb(y); a1[y].pb(x);
}
}
int sz;
int cnt;
void Add1(int lax,int lay,int nowx,int nowy){
e[nowx].pb({lax,nowx,lay,nowy});
e[nowy].pb({lay,nowy,lax,nowx});
}
void printh(int x){
vis[x] = 1;
for (int i = Linkk[x]; i; i = ee[i].Next){
int y = ee[i].y; int x0 = x , y0 = y;
if (ho[y] != ho[x]) continue;
if (x0 > y0) swap(x0,y0);
if (!Mat[{x0,y0}]) ans.pb({x,y}),Mat[{x0,y0}] = 1;
if (!vis[y]) printh(y);
}
}
void print(int x){
if (x > n) printh(x-n);
for (int i = 0; i < tr[x].size(); i++){
Ed X = tr[x][i];
if (X.u ==X.uu && X.v == X.vv){
ans.pb({X.uu,X.vv});
print(X.vv);
continue;
}
else if (X.u !=X.uu && X.v != X.vv){
ans.pb({X.u,X.v});
print(X.vv);
continue;
}
else if (X.u != X.uu){
ans.pb({X.u,X.vv});
print(X.vv);
continue;
}
else ans.pb({X.uu,X.v}),print(X.vv);
}
}
void Print(){
int st = 1; if (ish[st]) st = ho[st];
print(st);
printf("YES\n%d\n",ans.size());
for (int i = 0 ; i < ans.size(); i++){
int x = ans[i].first , y = ans[i].second;
printf("%d %d\n",x,y);
}
return ;
}
bool Vi[N],br[N];
int Num;
void dfs(int x){
Vi[x] = 1; Num++;
if (Num == cnt){
Print(); exit(0);
}
for (int i = 0; i < e[x].size(); i++){
int y = e[x][i].vv;
if (Vi[y]) continue;
tr[x].pb(e[x][i]);
dfs(y);
}
}
int ti = 0;
void Tarjan(int x,int La){
dfn[x] = low[x] = ++ti;
for (int i = Linkk[x]; i; i = ee[i].Next){
int y = ee[i].y;
if (!dfn[y]){
Tarjan(y,i);
low[x] = min(low[x],low[y]);
if (low[y] > dfn[x])
br[i] = br[i^1] = 1;
}
else if (i != (La^1))
low[x] = min(low[x],dfn[y]);
}
}
void Dfs(int x,int numb){
ho[x] = numb; sz++; ish[x] = 1;
for (int i = Linkk[x]; i; i = ee[i].Next){
int y = ee[i].y;
if (ho[y] || br[i]) continue;
Dfs(y,numb);
}
}
int main(){
scanf("%d %d",&n,&m);
memset(ish,1,sizeof ish);
for (int i = 1; i <= m; i++){
int x,y; string s; scanf("%d %d",&x,&y); cin>>s;
while (s.size() == 0) cin>>s;
if (s == "Lun") Add(x,y,0);
else if (s == "Qie") Add(x,y,1);
}
for (int i = 1; i <= n; i++) if (!dfn[i]) Tarjan(i,0);
for (int i = 1; i <= n; i++) if (!ho[i]){
sz = 0;
Dfs(i,i+n);
if (sz == 1) ho[i] = 0,ish[i] = 0;
}
memset(vis,0,sizeof vis);
for (int i = 1; i <= n; i++){
int x = i; if (ish[i]) x = ho[i];
if (vis[x]) continue; cnt++; vis[x] = 1;
}
for (int i = 1; i <= n; i++){
int x = i; if (ish[i]) x = ho[i];
for (int j = 0; j < a1[i].size(); j++){
int to = a1[i][j]; int y = to; if (ish[y]) y = ho[y];
if (x == y) continue;
Add1(i,to,x,y);
}
}
memset(vis,0,sizeof vis);
int st = 1; if (ish[st]) st = ho[st];
dfs(st);
cout<<"NO";
return 0;
}
Challenge NPC 2
简要题意就是给你一个森林,让你求补图是否存在哈密顿路径
无解的一个充分条件显然就是菊花图
但是不是充分必要条件呢?
我们考虑一棵树(不是菊花图)
他有若干层,每一层之间的儿子之间显然是没有连边的。
这说明什么?
每一层之间的几个点可以串联成一条小哈密顿路径。
问题就变成了,我们能不能到达每一层
如果树的直径>=4,答案显然是可以的
我们可以这样子走:
找出这棵树的直径,将直径的一端作为根(其实只要层数>=4都行,为了方便直接求直径即可)
先走2,4,6……偶数层,再走1,3,5……奇数层
这样,就能不重复的经过每一层
经过每一层的同时,在将这一层的节点遍历完即可。
因此,只要不是菊花图,一定能找出一种方法,遍历这个图
但是这是一个森林。
我们可以将他们连成一棵树再按照上面的方式游走。
其中之一的方案就是将这几个树的直径一次首尾相连变成一棵树
然后再按照上面的方式游走。
这里强调直径,并不是说一定要按照直径
而是因为用直径跑出来的树的深度更深,也就不存在不符合要求的可能。
对于
n
<
=
3
n<=3
n<=3的情况,特判即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
int n,m;
vector < int > a[N];
#define pb push_back
typedef pair < int , int > pii;
vector < pii > Ed;
vector < int > de[N];
#define gc getchar()
int re(){
int s = 0; char ch = gc;
while (ch < '0' || ch > '9') ch = gc;
while (ch >= '0' && ch <= '9') s = s*10+ch-48 , ch = gc;
return s;
}
bool Check(){
for (int i = 1; i <= n; i++)
if (a[i].size() == n-1) {return 1;}
return 0;
}
bool vis[N];
int d[N];
void Dfs(int x,vector < int >& ex){
ex.pb(x); vis[x] = 1;
for (int i = 0; i < a[x].size(); i++){
int y = a[x][i]; if (vis[y]) continue;
d[y] = d[x]+1;
Dfs(y,ex);
}
}
int cnt = 0,maxd;
void dfs(int x,int dd,int faa){
de[dd].pb(x); maxd = max(maxd,dd);
for (int i = 0; i < a[x].size(); i++){
int y = a[x][i]; if (y == faa) continue;
dfs(y,dd+1,x);
}
}
void Clear(){
for (int i = 1; i <= maxd; i++)
de[i].clear();
for (int i = 1; i <= n; i++) a[i].clear(); Ed.clear();
}
void Work(){
n = re(); m = re();
for (int i = 1; i <= n; i++) vis[i] = 0,d[i] = 0;
for (int i = 1,x,y; i <= m; i++)
x = re() , y = re() , a[x].pb(y) , a[y].pb(x);
if (Check()){
printf("-1\n"); Clear();
return ;
}
if (n == 2){
Clear();
cout<<1<<' '<<2<<endl; return;
}
if (n == 3){
if (m == 0){
Clear();
cout<<1<<' '<<2<<' '<<3<<endl; return;
}
if (m == 1){
if (a[1].size()){
if (a[1][0] == 2) cout<<1<<' '<<3<<' '<<2<<endl;
else cout<<1<<' '<<2<<' '<<3<<endl;
Clear();
return ;
}
Clear();
cout<<2<<' '<<1<<' '<<3<<endl;
return;
}
return ;
}
int La = 0;
for (int i = 1; i <= n; i++) if (!vis[i]){
vector < int > ex;
Dfs(i,ex);
int st,ed; st = i;
for (int j = 0; j <ex.size(); j++)
if (d[st] < d[ex[j]]) st = ex[j];
d[st] = 0;
for (int j = 0; j < ex.size(); j++) vis[ex[j]] = 0;
ex.clear();
Dfs(st,ex);
ed = i;
for (int j = 0; j <ex.size(); j++)
if (d[ed] < d[ex[j]]) ed = ex[j];
ex.clear();
if (La != 0) Ed.pb({st,La});
La = ed;
}
for (int i = 0; i < Ed.size(); i++){
int x = Ed[i].first , y = Ed[i].second;
a[x].pb(y); a[y].pb(x);
}
vector < int > ex; int st,ed;
for (int i = 1; i <= n; i++) d[i] = 0,vis[i] = 0;
Dfs(1,ex); st = 1;
for (int i = 1; i <= n; i++) vis[i] = 0;
for (int i = 1; i <= n; i++)
if (d[st] < d[i]) st = i;
d[st] = 0;
Dfs(st,ex); ed = st;
for (int i = 1; i <= n; i++) if (d[ed] < d[i]) ed = i;
maxd = 0;
dfs(st,1,0);
int la = 0;
for (int i = 2; i <= maxd; i+=2){
for (int j = 0; j < de[i].size(); j++)
cout<<de[i][j]<<' ',la = de[i][j];
}
for (int i = 1; i <= maxd; i+=2)
for (int j = 0; j < de[i].size(); j++)
cout<<de[i][j]<<' ';
cout<<endl;
Clear();
return;
}
int main(){
int t; t = re();
while (t--) Work();
return 0;
}
/*
5
5 2
1 5
2 3
5 4
1 2
1 3
2 4
2 5
*/