URAL 1040 Airline Company 构造,思路 难度:2

时间:2022-01-28 17:10:11

http://acm.timus.ru/problem.aspx?space=1&num=1040

题目要求在一个联通无向图中找出一种方法给边标号使得任意一个有多条边的点,边的号码的最大公约数都为1

想象在dfs树上,以1为根进入,将第一条边标为序号1,则节点1满足条件

剩下的边遵照dfs顺序表明,那么非叶节点一定满足从父亲到自身的树边和自身的另一条边序号相邻

所以直接dfs标号即可

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=51;
const int maxm=maxn*maxn;
int first[maxn];
struct edge{
int f,t,ind,nxt;
}e[maxm];
int elen;
int ind[maxm];
void addedge(int f,int t,int ind){
e[elen].f=f;
e[elen].t=t;
e[elen].ind=ind;
e[elen].nxt=first[f];
first[f]=elen++;
}
int n,m,cnt;
bool vis[maxn];
void dfs(int s){
vis[s]=true;
for(int p=first[s];p!=-1;p=e[p].nxt){
if(ind[e[p].ind]==0){
ind[e[p].ind]=++cnt;
int t=e[p].t;
if(!vis[t]){
dfs(t);
}
}
}
}
int gcd(int a,int b){
if(a<b)swap(a,b);
if(b==0)return a;
return gcd(b,a%b);
}
int main(){
scanf("%d%d",&n,&m);
memset(first,-1,sizeof(first));
for(int i=0;i<m;i++){
int f,t;
scanf("%d%d",&f,&t);
addedge(f,t,i);
addedge(t,f,i);
}
dfs(1);
for(int i=1;i<=n;i++){
int g=-1;
int len=0;
for(int p=first[i];p!=-1;p=e[p].nxt){
len++;
if(g==-1){
g=ind[e[p].ind];
}
else {
g=gcd(g,ind[e[p].ind]);
}
}
if(len>1&&g!=1){
puts("NO");
return 0;
}
}
puts("YES");
for(int i=0;i<m;i++){
printf("%d%c",ind[i],i==m-1?'\n':' ');
}
return 0;
}