HDU 4781 Assignment For Princess

成都区域赛题目。


题意:


给你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;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值