成都区域赛题目。
题意:
给你n个点,m条边,边权分别是1,2,3...m
构造一张有向图,条件是:
1.强连通
2.两点之间只能有一条有向边
2.任意一个环的权值和必须能被3整除。
思路:
把边权先mod 3,这样就转换成0,1,2三种边。
然后我们的过程是这样:
1.先把n个点串起来,连一个大环。用1,2的边(成对使用)(1+2%3==0),如果不够就用0的边。需要注意,如果n为奇数,那么有可能会单独连一条1的边,这样就不符合要求了,所以1的这条要替换成0。
2.我们的目的是要把所有边使用完,然后我们现在再来消耗1的边。设入边是2(边权为2指向该点的有向边)的点为u,出边是2的点为v,显然可以连一条u->v。找到所有这样的(u,v)。同理入边是1,出边是1,消耗2的边。
3.最后来消耗0,0的选择就比较多了。
a.入边是1,出边是2
b.入边是2,出边是1
c.入边是0,出边是0
全部消耗完后,还有剩余边的话,那么将无法完成任务。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 100010
#define ll long long
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD =1000000007;
const double EPS=1e-7;
struct Edge{
int u,v,c;
Edge(){}
Edge(int u,int v,int c):u(u),v(v),c(c){};
bool operator<(const Edge &edge)const{
return c<edge.c;
}
}e[N];
int n,m,cnt[3],eid;
bool mp[128][128];
vector<int> in[3],out[3];
void add(int x,int y,int c){
e[eid++]=Edge(x,y,c);
cnt[c]--;
mp[x][y]=true;
mp[y][x]=true;
out[c].push_back(x);
in[c].push_back(y);
}
void gao(int c,int x,int y){
for(int i=0;cnt[c] && i<in[x].size();i++){
for(int j=0;cnt[c] && j<out[y].size();j++){
int u=in[x][i], v=out[y][j];
if(mp[u][v] || u==v) continue;
add(u,v,c);
}
}
}
bool makeMap(){
int who=1,i;
int num=min(cnt[1],cnt[2])*2;
CLR(mp,0);
eid=0;
for(int i=0;i<3;i++)
in[i].clear(), out[i].clear();
for(i=1;num && i<n;i++,num--){
add(i,i+1,who);
who=3-who;
}
if(n%2 || i<n){
for(;i<=n;i++){
if(cnt[0]) add(i,i%n+1,0);
else return false;
}
}else{
add(n,1,who);
}
for(int c=1;c<=2;c++) gao(c,3-c,3-c);
gao(0,1,2);
gao(0,2,1);
gao(0,0,0);
if(cnt[0]+cnt[1]+cnt[2]) return false;
return true;
}
void output(){
int ans[3]={3,1,2};
for(int i=0;i<m;i++){
printf("%d %d %d\n",e[i].u,e[i].v,ans[e[i].c]);
ans[e[i].c]+=3;
}
}
int main(){
int re,Case=1;
scanf("%d",&re);
while(re--){
scanf("%d%d",&n,&m);
CLR(cnt,0);
for(int i=1;i<=m;i++) cnt[i%3]++;
printf("Case #%d:\n",Case++);
if(makeMap()) output();
else puts("-1");
}
return 0;
}