题目大意来自网上众多博客的大神翻译。
题目大意:有一个n个点,m条边的有向图,每条边的权值分别为1,2,3........m,让你构造满足下列条件的有向图。
1:每两个点之间最多只有一条有向边,且不存在自环。
2:从任意点出发都可以达到其他任意一个点,包括自己。
3:任意一个有向环的权值和都是3的倍数。
思路:首先我们可以将点1到n连成一条链,边的权值分别是1到n-1,然后点n到点1连一条边,这个时候体现出了一条规律,若n%3为0或2,则加上的边边权值为n,否则边权值为n+2。(对于本人来说这是条规律)
现在我们构造出了一个环且满足上述三个条件。
现在只需要在I和J两个点之间连其他线就好了,需要满足的条件是len%3==I和J之间原链上的距离%3.代码还需要判断这两个点是否已经有过连线,否则继续暴力。
可能因为脸黑,函数里面的循环里面写RETURN 1;会被OJ爆出CE,改成flag版本莫名其妙就过了。
代码如下:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>
using namespace std;
typedef struct{
int from;
int to;
int len;
}an;
int h[3]={0,2,0};
an ans[5010];
int mp[100][100];
int vis[5010];
int sum[100];
long long n;
int solve(int len,int num)
{
int temp = len%3;
int flag = 0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i!=j&&mp[i][j]!=1&&mp[j][i]!=1)
{
if((sum[j]-sum[i]+3)%3==temp)
{
ans[num].from = i;
ans[num].to = j;
ans[num].len = len;
mp[i][j] = 1;
flag =1;
break;
}
}
}
if(flag == 1 )break;
}
return flag;
}
int main()
{
long long T;
cin >> T;
long long g=1;
while(T--)
{
long long m;
cin >> n >> m;
memset(sum,0,sizeof(sum));
memset(vis,0,sizeof(vis));
memset(mp,0,sizeof(mp));
for(int i=1;i<n;i++)
{
ans[i].from = i;
ans[i].to = i+1;
ans[i].len = i;
vis[i] = 1;
mp[i][i+1] = 1;
if(i!=1)
sum[i] = (i-1+sum[i-1])%3;
}
//开始构造封闭的环。
ans[n].len = n+h[n%3];
ans[n].from = n;
ans[n].to = 1;
vis[ans[n].len]=1;
mp[n][1] = 1;
sum[n] = (n-1+sum[n-1])%3;
//开始加其他边;
int num=n,flag = 1;
for(int i=1;i<=m;i++)
{
if(!vis[i])
{
flag = solve(i,++num);
if(!flag)
break;
}
}
cout<<"Case #"<<g++<<":"<<endl;
if(flag==0)cout<<-1<<endl;
else
{
for(int i=1;i<=m;i++)
{
cout<<ans[i].from<<" "<<ans[i].to<<" "<<ans[i].len<<endl;
}
}
}
return 0;
}