zoukankan      html  css  js  c++  java
  • 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 ightarrow 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:
    ", kase);
    		if(ok) {
    			for(int i = 0; i < m; i++)
    				printf("%d %d %d
    ", edges[i].u, edges[i].v, edges[i].d);
    		}
    		else printf("-1
    ");
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    【作业】Python面向对象
    Python使用使用第三方源(国内源:豆瓣)下载包文件 超快!!!
    【案例】Python
    【个人笔记】Python
    定义函数相关内容
    列表,for循环相关.
    while应用和函数学习
    斗地主发牌器
    字符串索引切片.
    随机生成20以内加减法,5次答题并统计正确和错误题数
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4911285.html
Copyright © 2011-2022 走看看