HDU 4781 Assignment For Princess 构造

题意:

构造一个\(N(10 \leq N \leq 80)\)个顶点\(M(N+3 \leq M \leq \frac{N^2} {7})\)条边的有向图,要满足如下条件:

  • 每条边有一个\([1,M]\)之间的权值,而且每条边的权值都是独一无二的
  • 该有向图是强联通的,即任意两点都互相可达
  • 图没有自环,而且任意两点之间最多有一条边
  • 可以从任意一点出发,经过任意条边,一条边可以走多次,再回到出发点
  • 符合上述要求的路径权值之和为3的倍数

分析:

首先我们构造一个长度为\(N\)的环,而且环的权值之和为3的倍数。
构造过程如下:

在顶点\(i\)\(i+1\)之间连一条长度为\(i\)的有向边,然后在\(N \sim N+2\)之间选一个使得整个环权值和为3的倍数,把这个作为边\((N,1)\)的权值。

这样我们得到的图就满足题目中的要求,但是还剩下\(M-N\)条边没有处理。
对于还没有选用的权值\(w\),选择一对没有连边的顶点\((u,v)\)
\(u \rightarrow v\)的路径上的权值和为\(sum\),如果\(w \equiv sum \: (mod 3)\),那么就在这两点之间连边。
这样添边的过程,依然使得原图的性质满足题目要求。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn = 80 + 10;
const int maxm = 1000;

int G[maxn][maxn], dis[maxn][maxn];

struct Edge
{
	int u, v, d;
	Edge() {}
	Edge(int u, int v, int d):u(u), v(v), d(d) {}
};

int n, m;
int ecnt;
Edge edges[maxm];
bool vis[maxm];

void AddEdge(int u, int v, int d) {
	edges[ecnt++] = Edge(u, v, d);
	G[u][v] = G[v][u] = true;
}

int main() {
	int T; scanf("%d", &T);
	for(int kase = 1; kase <= T; kase++) {
		scanf("%d%d", &n, &m);

		memset(vis, false, sizeof(vis));
		memset(G, false, sizeof(G));
		ecnt = 0;

		for(int i = 1; i < n; i++) {
			AddEdge(i, i + 1, i);
			vis[i] = true;
		}
		int sum = (n * (n - 1) / 2) % 3, tmp;
		for(int i = n; ; i++) if((i + sum) % 3 == 0) {
			vis[i] = true;
			AddEdge(n, 1, i);
			tmp = i;
			break;
		}

		for(int i = 2; i <= n; i++) {
			dis[i-1][i] = (i - 1) % 3;
			dis[i][i-1] = (3 - dis[i-1][i]) % 3;
			for(int j = i - 2; j >= 1; j--) {
				dis[j][i] = (dis[j][i-1] + dis[i-1][i]) % 3;
				dis[i][j] = (3 - dis[j][i]) % 3;
			}
		}
		dis[n][1] = tmp % 3;
		for(int i = 2; i < n; i++) dis[n][i] = (dis[n][1] + dis[1][i]) % 3;

		bool ok = true;
		for(int i = n; i <= m; i++) if(!vis[i]) {
			bool findit = false;
			for(int u = 1; u <= n; u++) {
				for(int v = 1; v <= n; v++) if(u != v) {
					if(dis[u][v] % 3 == i % 3 && !G[u][v]) {
						findit = true;
						AddEdge(u, v, i);
						break;
					}
				}
				if(findit) break;
			}
			if(!findit) { ok = false; break; }
		}

		printf("Case #%d:\n", kase);
		if(ok) {
			for(int i = 0; i < m; i++)
				printf("%d %d %d\n", edges[i].u, edges[i].v, edges[i].d);
		}
		else printf("-1\n");
	}

	return 0;
}
posted @ 2015-10-26 15:24  AOQNRMGYXLMV  阅读(162)  评论(0编辑  收藏  举报