hdu 4781 Assignment For Princess(构造法)

构造一个n个点,m条有向边的图,需要满足两个要求:

1.任意一对点对之间最多有一条有向边,且没有自环。

2.保证图联通,m条边的边权严格属于[1, m]且互不相同,从任意点出发,经过任意路径后回到起始点,经过的边权总和是3的倍数。

其中第二个要求似乎听上去很玄乎,其实可以一步一步的来:要同时满足1.2的要求,而且输入数据 m >= n + 3,那么也就是说,我们总是能轻松的先构造一个n个点n条有向边的环,其中前n-1条边的边权是1...2..3...n-1,对于最后一条边,可以取n, n+1或 n+2,总之使得这个环的总权值tot%3==0就行了。

这样的话,我们就完成了初步建图:已经构造了一个n个点n条边且满足题意的图了,那么对于剩下的m-n条边怎么办?如果我们需要在原有的环上添加一条边权为w的边,并且还要维护图的1.2性质,显然,我们只需要找到这样一个点对<u, v>,其中在我们构造的初始环上,u - > v 的距离为g[u][v], 那么只需要g[u][v] % 3 == w % 3,我们就能保证图的性质不变了!

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define REP(i, n) for(int i=0; i<n; i++)
#define FF(i, a, b) for(int i=a; i<b; i++)
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100;
int n, m, T, g[maxn][maxn], dist[maxn][maxn];
bool vis[10000];
vector<pair<int, int> > edges;
vector<int> G[maxn];

bool gao(int x)
{
    FF(i, 1, n+1) FF(j, 1, n+1) if(i != j)
    {
        if(dist[i][j] == 0 && dist[j][i] == 0)
        {
            if(g[i][j] % 3 == x % 3)
            {
                dist[i][j] = x;
                return true;
            }
        }
    }
    return false;
}

bool solve()
{
    FF(i, 1, m+1) if(!vis[i])
        if(!gao(i)) return false;
    return true;
}

int dfs(int u, int pos, int fa, int len)
{
    if(u == pos) return len;
    REP(i, G[u].size())
    {
        int v = edges[G[u][i]].first, w = edges[G[u][i]].second;
        if(v != fa) return dfs(v, pos, u, len+w);
    }
}

void build()
{
    CLR(vis, 0); CLR(dist, 0);
    REP(i, n+1) G[i].clear();   edges.clear();
    int tot = 0, sz = 0;
    FF(i, 1, n)
    {
        edges.push_back(make_pair(i+1, i));
        G[i].push_back(sz++);
        vis[i] = 1; dist[i][i+1] = i;
        tot += i;
    }
    FF(i, n, n+3) if((tot + i) % 3 == 0)
    {
        edges.push_back(make_pair(1, i));
        G[n].push_back(sz);
        vis[i] = 1; dist[n][1] = i;
        break;
    }
    FF(i, 1, n+1) FF(j, 1, n+1)
        g[i][j] = dfs(i, j, -1, 0);
}

int main()
{
    scanf("%d", &T);
    FF(kase, 1, T+1)
    {
        scanf("%d%d", &n, &m);
        build();
        printf("Case #%d:\n", kase);
        if(solve())
        {
            FF(i, 1, n+1) FF(j, 1, n+1) if(dist[i][j])
                printf("%d %d %d\n", i, j, dist[i][j]);
        }
        else puts("-1");
    }
    return 0;
}


  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值