2013-2014 ACM ICPC Central European Regional Contest (CERC 13) K-Digraphs
题意
要求构造一个字符方阵。给定n对字符,每对字符表示这两个字符不能出现在方阵中,输出方案
思路
很容易想到两个字符间连一条有向边,构成一张有向图,遍历它的补图,若该补图有环,则输出这个环,注意环的长度若大于20要截取;若无环,则输出最长链。
问题转化为给定一张有向图,找环,若无环,找最长链。做法是枚举起点dfs找最长链,在搜索过程中记录点的状态,当搜到点cur时,若cur到起点u有边,则找到环,此时cir记为1,便于回溯时剪枝。一开始用vector存储路径但是一直wa也搞不清问题在哪,仿照别人用的数组才过,可是看上去没差别啊
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ms(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const int M = int(1e5) + 5;
const int mod = int(1e9) + 7;
int g[50][50];
bool vis[30];
// vector<int> path;
// vector<int> tem;
int path[M];
int tem[M];
int plen;
bool cir;
bool dfs(int u,int cur,int len){
vis[cur]=1;
if(cir==1){
return true;
}
if(g[cur][u]==0 && vis[u]){
cir=1;
// tem.push_back(cur);
// path=tem;
plen=len;
path[len]=cur;
memcpy(path,tem,sizeof(path));
return true;
}
bool flag=0;
for(int i=0;i<26;i++){
if(g[cur][i]==0 && !vis[i]){
flag=1;
// tem.push_back(i);
tem[len]=i;
if(dfs(u,i,len+1)){
return true;
}
vis[i]=0;
// tem.pop_back();
}
}
if(flag==0){
// if(path.size()<tem.size()){
// path=tem;
// }
if(len>plen){
memcpy(path,tem,sizeof(path));
plen=len;
}
}
return false;
}
int main(){
int t;
cin>>t;
while(t--){
// path.clear();
// tem.clear();
ms(path);
ms(tem);
cir=0;
ms(g);
plen=0;
int n;
cin>>n;
while(n--){
char a,b;
cin>>a>>b;
g[a-'a'][b-'a']=-1;
}
for(int i=0;i<26;i++){
ms(vis);
// tem.push_back(i);
tem[0]=i;
// vis[i]=1;
// int t=0;
// while(t<26 && g[i][t]==-1){
// t++;
// }
// if(t==26){
// continue;
// }
if(dfs(i,i,1)){
break;
}
// tem.clear();
}
// int len=path.size();
if(cir==1){
for(int i=0;i<20;i++){
for(int j=0;j<20;j++){
cout<<(char)(path[(j+i%plen)%plen]+'a');
}
cout<<endl;
}
}
else{
// len=max(len,39);
int nn=plen + 1 >> 1;
for(int i=0;i<nn;i++){
for(int j=0;j<nn;j++){
cout<<(char)(path[(j+i)]+'a');
}
cout<<endl;
}
}
}
return 0;
}
————————————————
心里有光,哪儿都美
心里有光,哪儿都美