L3-015. 球队“食物链”
某国的足球联赛中有N支参赛球队,编号从1至N。联赛采用主客场双循环赛制,参赛球队两两之间在双方主场各赛一场。
联赛战罢,结果已经尘埃落定。此时,联赛主席突发奇想,希望从中找出一条包含所有球队的“食物链”,来说明联赛的精彩程度。“食物链”为一个1至N的排列{ T1 T2 ... TN },满足:球队T1战胜过球队T2,球队T2战胜过球队T3,……,球队T(N-1)战胜过球队TN,球队TN战胜过球队T1。【像是构成了一个遍历了所有节点一次的回路或者可以形成了一个环;那么如果存在,起点1一定可以做开头!毕竟可以形成一个环!】
现在主席请你从联赛结果中找出“食物链”。若存在多条“食物链”,请找出字典序最小的。【按照DFS进行有序搜索,一定满足字典序!】
注:排列{ a1 a2 ...aN }在字典序上小于排列{ b1 b2 ... bN },当且仅当存在整数K(1 <= K <= N),满足:aK < bK且对于任意小于K的正整数i,ai=bi。【等价于字典序的解释吧】
输入格式:
输入第一行给出一个整数N(2 <= N <= 20),为参赛球队数。随后N行,每行N个字符,给出了NxN的联赛结果表,其中第i行第j列的字符为球队i在主场对阵球队j的比赛结果:“W”表示球队i战胜球队j,“L”表示球队i负于球队j,“D”表示两队打平,“-”表示无效(当i=j时)。输入中无多余空格。
【这里需要再注意一点,mp[i][j]=='L' 等价于 mp[j][i]='W' ,这两个语句等可以表达出 i 战胜过j ;第二次WA的时候仔细揣摩了上面的那几个“过”字,有所新的领悟了!】
AC题解如下:
基础搜索即可,保证有序:
1、第一次剪枝加了句,if(ans==1)return ; //此处剪枝,多获得三分
2、第二次剪枝,把图转化成了邻接矩阵!//然并卵
3、第三次剪枝,在每次向下进行迭代的时候,跑一遍for循环——如果没有一个点可以回连到起点1就return ,就是下面未标记的解集里没有可以再回去连接到出发点1的路径了!
(写的时候省了点事,从下标0到n-1进行遍历,正好符合字符串的存贮位置!!)
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<math.h> 5 #include<algorithm> 6 #include<queue> 7 #include<set> 8 #include<vector> 9 #include<string> 10 #include<stack>//16:06-- 11 #define inf 0x3f3f3f3f 12 #define dinf 0x7fffffff*1.0 13 using namespace std; //L3-015. 球队“食物链” 14 #define N 1200 15 #define ll long long 16 int n; 17 char mp[22][22]; 18 int ans; 19 int tmp[22];//存贮结果的数组 20 int vis[22];//标记行 21 vector<int>G[22];//然并卵的邻接矩阵 22 void dfs(int k,int step){//k表示要搜索的下一行的标号,step表示已经完成的行数 23 // printf("k=%d step=%d ",k,step); 24 if(ans==1)return ; //此处剪枝,多获得三分 25 tmp[step]=k+1; 26 if(step==n-1){ 27 if(mp[k][0]=='W'){ 28 ans=1; 29 } 30 return ; 31 } 32 int i; 33 for( i=0;i<n;i++){ 34 if(!vis[i]&&(mp[i][0]=='W')) 35 break; 36 } 37 if(i==n)return ;//存在未收录的点不与1相连,就是下面未确认的解集里没有可以连接到出发点0的路径了 38 39 for( i=0;i<G[k].size();i++){ 40 int v=G[k][i];//取出k战胜过的队伍编号 41 if(!vis[v]){ 42 vis[v]=1; 43 dfs(v,step+1); 44 vis[v]=0; 45 } 46 } 47 } 48 void get_graph(){//生成邻接矩阵 49 for(int i=0;i<n;i++){ 50 for(int j=0;j<n;j++){ 51 if(mp[i][j]=='W'){ 52 G[i].push_back(j); 53 } 54 } 55 } 56 } 57 int main(){ 58 59 while(~scanf("%d",&n)){ 60 for(int i=0;i<=20;i++)//初始化邻接矩阵 61 G[i].clear(); 62 for(int i=0;i<n;i++){ 63 scanf("%s",mp[i]); 64 } 65 for(int i=0;i<n;i++){ 66 for(int j=0;j<n;j++){ //mp[i][j]=='L' 等价于 mp[j][i]='W' 67 if(mp[i][j]=='L'){ 68 if(mp[j][i]=='L') 69 mp[i][j]='W'; 70 mp[j][i]='W'; 71 } 72 } 73 } 74 get_graph();//存成邻接矩阵 75 ans=0; 76 tmp[0]=1; 77 for(int i=0;i<n;i++){ 78 memset(vis,0,sizeof(vis)); 79 vis[0]=1; 80 if(mp[0][i]=='W'){ 81 vis[i]=1; 82 dfs(i,1); 83 } 84 if(ans==1)break; 85 } 86 if(ans==1){ 87 for(int i=0;i<n-1;i++) 88 printf("%d ",tmp[i]); 89 printf("%d ",tmp[n-1]); 90 }else{ 91 printf("No Solution "); 92 } 93 } 94 95 return 0; 96 } 97 98 /* 99 3 100 -LL 101 L-L 102 LL- 103 */