一道感觉挺好玩的通信题。
首先这应该是到二合一的题目,Subtask 1-4 和 Subtask 5-7 没有什么共通的方法。
首先看 Subtask 1-4,要求一点都不能走错,可以使用 (3) 种标记,图形态没有保证。
做法是先 bfs 一遍,把图分层,分完层之后的图只有 (2) 种边:相邻两层之间的边 和 同一层内部的边。
显然需要把一个点向前一层的边和向后一层的边用两种标记区分开来,然后发现同一层内部的边和向后一层的边都是不能走的边,可以用同一种标记,然后考虑用第三种标记来说明当前点应该要往哪里走。
发现层间的边使用 (0,1,2,0,1,2...) 的标号方法可以达成目标,若只有一种标记,只要走那种标记;若有两种标记,设剩下来的标记为 (x) ,只要走 ((x+1)mod 3) 即可。
然后看 Subtask 5-7,要求可以走错 (3) 次,但只能用两种标记,图保证是树。
显然不能用前面的方法。
仔细分析之后,发现如果树如果没有退化成链,可以简单地通过将连向祖先的边标不同的标记来区分出来,而在链上难以区分上下。
所以只要能够在链上区分出上下,这题就做完了。
发现题目给的条件只有标号,所以问题转化为了找到一个尽可能短的 (0,1) 序列,使得他无论从哪个位置开始,正着读和反着读都不同。
然后发现一个可行的序列是 (0,0,1,1,0,1) 循环,但他至少要读 (5) 位才能保证不同,一个解决的办法是把开头的 (2) 个都放进去,最后一个不走过去,然后立即判断(感觉此处表述不太清晰,可以看代码理解)。
于是这道题在算法上被解决了,感觉实现的时候 Subtask 5-7 有点麻烦,还容易写错。
Code Anthony :
#include "Anthony.h"
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define Fast_IO ios::sync_with_stdio(false)
#define DEBUG fprintf(stderr,"Running on Line %d in Function %s
",__LINE__,__FUNCTION__)
#define fir first
#define sec second
#define mod 998244353
#define INF 0x3fffffff
#define ll long long
typedef pair<int,int> pii;
namespace Sub1
{
const int N=20005;
vector<int> G[N],id[N];
int dep[N];
vector<int> Main(int n,int m,vector<int> u,vector<int> v)
{
for(int i =0;i<m;i++) G[u[i]].push_back(v[i]),G[v[i]].push_back(u[i]);
dep[0]=1;
queue<int> q; q.push(0);
while(!q.empty())
{
int u=q.front(); q.pop();
for(int v:G[u])
{
if(!dep[v])
{
dep[v]=dep[u]+1;
q.push(v);
}
}
}
vector<int> ans;
for(int i=0;i<m;i++)
{
int R=min(dep[u[i]],dep[v[i]]);
ans.push_back(R%3);
}
return ans;
}
};
int t[]={0,0,1,1,0,1};
namespace Sub2
{
const int N=20005;
vector<pii> G[N];
int ans[N];
void dfs(int u,int fa,int len,int col)
{
if(fa==-1)
{
if(G[u].size()==1)
{
ans[G[u][0].sec]=0;
dfs(G[u][0].fir,u,1,1);
}
else
{
for(pii v:G[u])
{
ans[v.sec]=0;
dfs(v.fir,u,0,1);
}
}
}
else
{
if(G[u].size()==2)
{
pii v;
for(pii i:G[u]) if(i.fir!=fa) v=i;
if(len==0&&col==1) len=2;
ans[v.second]=t[len%6];
dfs(v.first,u,len+1,ans[v.second]^1);
}
else
{
for(pii v:G[u])
{
if(v.fir==fa) continue;
ans[v.second]=col;
dfs(v.first,u,0,col^1);
}
}
}
}
vector<int> Main(int n,int m,vector<int> u,vector<int> v)
{
for(int i=0;i<m;i++) G[u[i]].push_back(mp(v[i],i)),G[v[i]].push_back(mp(u[i],i));
dfs(0,-1,0,0);
vector<int> R(m);
for(int i=0;i<m;i++) R[i]=ans[i];
return R;
}
};
vector<int> Mark(int N,int M,int A,int B,vector<int> U,vector<int> V)
{
if(A>=3) return Sub1::Main(N,M,U,V);
else return Sub2::Main(N,M,U,V);
}
Code Catherine :
#include "Catherine.h"
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define Fast_IO ios::sync_with_stdio(false)
#define DEBUG fprintf(stderr,"Running on Line %d in Function %s
",__LINE__,__FUNCTION__)
#define fir first
#define sec second
#define mod 998244353
#define INF 0x3fffffff
#define ll long long
typedef pair<int,int> pii;
namespace {
int A, B;
int variable_example = 0;
} // namespace
namespace Sub1
{
int Main(vector<int> a)
{
int cnt=0;
for(int i=0;i<3;i++) if(a[i]) cnt++;
if(cnt==1)
{
if(a[0]) return 0;
if(a[1]) return 1;
if(a[2]) return 2;
}
else
{
if(!a[0]) return 1;
if(!a[1]) return 2;
if(!a[2]) return 0;
}
}
};
bool dir=0;
int las=-1;
vector<int> v;
// 0,0,1,1,0,1
namespace Sub2
{
int Main(vector<int> a)
{
if(las==-1)
{
if(a[0]+a[1]==2)
{
if(a[0]==2)
{
v.push_back(0); v.push_back(0); // 把开头的 2 个都放进去
return 0;
}
if(a[1]==2)
{
v.push_back(1); v.push_back(1);
return 1;
}
v.push_back(1); v.push_back(0);
return 0;
}
if(!a[0])
{
dir=1; return 1;
}
if(!a[1])
{
dir=1; return 0;
}
if(a[0]&&a[1]&&(a[0]>1||a[1]>1))
{
dir=1;
if(a[0]==1) return 0;
if(a[1]==1) return 1;
}
assert(0);
}
if(a[0]==0&&a[1]==0)
{
dir=1;
return -1;
}
if(!dir)
{
if(a[0]+a[1]>1)
{
a[las]++; dir=1;
if(a[0]==1&&las!=0) return 0;
if(a[1]==1&&las!=1) return 1;
assert(a[las]==1);
return -1;
}
if(a[0]) v.push_back(0);
else v.push_back(1);
if(v.size()==5)
{
dir=1;
bool tr=1;
if(v[0]==0&&v[1]==0&&v[2]==1&&v[3]==1&&v[4]==0) tr=0;
if(v[0]==0&&v[1]==1&&v[2]==1&&v[3]==0&&v[4]==1) tr=0;
if(v[0]==1&&v[1]==1&&v[2]==0&&v[3]==1&&v[4]==0) tr=0;
if(v[0]==1&&v[1]==0&&v[2]==1&&v[3]==0&&v[4]==0) tr=0;
if(v[0]==0&&v[1]==1&&v[2]==0&&v[3]==0&&v[4]==1) tr=0;
if(v[0]==1&&v[1]==0&&v[2]==0&&v[3]==1&&v[4]==1) tr=0;
if(!tr) return -1;
else return v.back();
}
else return v.back();
}
else
{
if(a[0]==0) return 1;
if(a[1]==0) return 0;
if(a[0]==1&&a[1]==1)
{
if(las==-1) return 5;
a[las]++;
}
if(a[0]==1) return 0;
if(a[1]==1) return 1;
return 2;
}
}
};
void Init(int A, int B) {
::A = A;
::B = B;
}
int Move(vector<int> y)
{
if(::A>=3) return Sub1::Main(y);
else
{
int res=Sub2::Main(y);
if(res==-1) return -1;
las=res; return res;
}
}