本题的两个条件:
首先,构造一个图,共有m条边,边权为1 - m互不相同。
图上任意两点间最多有一条有向边,
其次,任意一点经过任意路径回到该点的权值和对3取余为0。
分析:
首先构造一个n个边的有向环,1->2->3...->n->1 ,前n-1条边的权值为1->(n-1),而第n条边为(n,n+1,或者n+2)使得sum%3=0;
那么,这个有向环是符合题意的,只是一些边权为特定值的边还未添加,那么只需在图上找到 dis(i,j)%3 == x%3,那么便可以添加。
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
#define rep(i,n) for(int i=0;i<int(n);i++)
#define rep1(i,x,y) for(int i=x;i<=(int)y;i++)
typedef long long ll;
const int N = 85;
int n,m,vis[N][N],val[N][N],ans[N][N],hav[N*N];
int cal(int x){
rep1(i,1,n)rep1(j,1,n)if(i!=j){
if(vis[i][j] || vis[j][i] ) continue;
if(val[i][j] % 3 == x % 3){
ans[i][j]=x;
hav[x] = 1;
vis[i][j]=1;
return 1;
}
}
return 0;
}
struct node{
int to,v;
node(int to=0,int v=0):to(to),v(v){}
};
vector<node> G[N];
int dis(int s,int t,int fa,int now){
if(s == t) return now;
rep(i,G[s].size())if(G[s][i].to!=fa){
return dis(G[s][i].to,t,s,now+G[s][i].v);
}
}
int init(){
for(int i=1;i<=n;i++) G[i].clear();
memset(vis,0,sizeof(vis));
memset(hav,0,sizeof(hav));
int sum = 0;
for(int i=1;i<=n-1;i++){
int x = i, y=i+1;
vis[x][y] = 1;
ans[x][y] = i;
G[x].push_back(node(y,i));
sum+=i;
hav[i]=1;
}
for(int i=n;i<=m;i++){
if((sum+i)% 3== 0){
hav[i] = 1;
vis[n][1] = 1;
ans[n][1] = i;
G[n].push_back(node(1,i));
break;
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
if(i!=j) val[i][j] = dis(i,j,-1,0);
for(int i=1;i<=m;i++)if(!hav[i]){
if(!cal(i)) return 0;
}
return 1;
}
int main()
{
int T,kase=1;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
printf("Case #%d:\n",kase++);
if(init()){
rep1(i,1,n) rep1(j,1,n){
if(vis[i][j]) {
printf("%d %d %d\n",i,j,ans[i][j]);
}
}
}
else printf("-1\n");
}
return 0;
}