UVALive 6590 Digraphs

题意:

有n个只包含两个字母的字符串, 要求构造一个m*m的字母矩阵, 使得矩阵的每行每列都不包含所给的字符串, m要尽量大, 如果大于20的话构造20*20的矩阵就行了。

思路:

对每个字符串第一个字母连向第二个字母一条有向边, 然后取它的补图。

在补图上,如果有环的话, 取环上的字母就一定可以构造上20*20的矩阵, 如果没环的话矩阵一定是用最长路来构造,假设最长路长度为len, 则矩阵大小为(len+1)/2。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <stack>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <ctime>
#include <cstdlib>
using namespace std;

#define mxn 30
#define mxe 900
#define mod 10000007
#define LL long long
#define inf 0x3f3f3f3f
#define vi vector<int>
#define PB push_back
#define MP make_pair
#define pii pair<int, int>
#define G(i, u) for(int i = fst[u]; ~i; i = nxt[i])
#define F(i, n) for(int i = 1; i <= n; ++i)
#pragma comment(linker,"/STACK:1024000000,1024000000")
#define ls (i << 1)
#define rs (ls | 1)
#define md ((ll + rr) >> 1)

bool g[mxn][mxn];
int pre[mxn];
int n;
char ans[mxn][mxn];
int dp[mxn];

bool bfs(int s) {
	queue<int> q;
	q.push(s);
	memset(pre, -1, sizeof pre);
	while(!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = 0; i < n; ++i) {
			if(g[u][i] == 0) continue;
			int v = i;
			if(v == s) {
				pre[s] = u;
				return 1;
			}
			if(pre[v] == -1) {
				pre[v] = u;
				q.push(v);
			}
		}
	}
	return 0;
}

int dfs(int u) {
	if(dp[u] != -1) return dp[u];
	dp[u] = 1;
	for(int i = 0; i < n; ++i) {
		if(g[i][u] == 0) continue;
		int tmp = dfs(i) + 1;
		if(tmp + 1 > dp[u])
			dp[u] = tmp + 1, pre[u] = i;
	}
	return dp[u];
}
int main() {
//	freopen("tt.txt", "r", stdin);
	int cas;
	scanf("%d", &cas);
	n = 26;
	while(cas--) {
		memset(g, 1, sizeof g);
		int t;
		scanf("%d", &t);
		if(t == 0) {
			for(int i = 0; i < 20; ++i)
				for(int j = 0; j < 20; ++j) {
					printf("%c", 'a');
					if(j == 19)
						puts("");
				}
			continue;
		}
		while(t--) {
			char s[3];
			scanf("%s", s);
			g[s[0]-'a'][s[1]-'a'] = 0;
		}

		int lp = -1;
		for(int i = 0; i < n; ++i) {
			if(bfs(i)) {
				lp = i;
				break;
			}
		}
	//	printf("%d\n", lp);
		if(lp != -1) {
			int cnt = 0;
			char s[30];
			for(int i = pre[lp]; i != lp; i = pre[i]) {
				s[cnt++] = i + 'a';
			}
			s[cnt++] = lp + 'a';
			reverse(s, s + cnt);
			s[cnt] = '\0';
		//	puts(s);
			for(int i = 0; i < 20; ++i) {
				for(int j = 0; j < 20; ++j)
					ans[i][j] = s[(i+j)%cnt];
				ans[i][20] = '\0';

			}
			for(int i = 0; i < 20; ++i)
				printf("%s\n", ans[i]);
			continue;
		}
		memset(dp, -1, sizeof dp);
		memset(pre, -1, sizeof pre);
		int id = -1;
		for(int i = 0; i < 26; ++i) {
			int tmp = dfs(i);
			if(id == -1 || tmp > dp[id])
				id = i;
		}
		char s[mxn];
		int cnt = 0;
		for(int i = id; i != -1; i = pre[i])
			s[cnt++] = i + 'a';
		reverse(s, s + cnt);
		if(cnt % 2 == 0)
			--cnt;
		int len = (cnt + 1) / 2;
		for(int i = 0; i < len; ++i) {
			for(int j = 0; j < len; ++j)
				ans[i][j] = s[(i+j)%cnt];
			ans[i][len] = '\0';
			printf("%s\n", ans[i]);
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值