题目分析:
1. 一场双循环赛制的篮球赛,注意双循环,双循环!
2. 共有n只球队,两两之间有胜有负有平局;
3. 输入:
举例:
第一行:W:代表球队1打赢过这只队伍
L:代表球队2没打赢过这只队伍
因为两队伍有两场比赛,所以互相都可能打败对方;
如果A队打赢过B队,就连一条A到B的有向边;
建边时注意,如果A队 "L" B队,就连一条B->A边;(忘了这个wa了一发)
(这是坑点1,不是最可怕的)
4. 目的:
找到一条食物链:1 3 5 4 2;
代表:1赢过3,3赢过5,5赢过4,4赢过2,并且 2赢过1
要循环的;
解题思路:
1. 很明显dfs可以解决;如果A队打赢过B队,就连一条A到B的有向边;
(因为我很傻以为球队有很多只,怕超时,sb的用set写,其实这个二维数组建边就行了,不过两种写法差别不大,我就当作 是温习一下set的知识。结果被set一个坑点卡了一晚上,贼气,我在结尾说这个蛋疼的故事)
2. 减枝:状压一下吧(应该是叫状压吧?唉,我太菜了)
state[cur][i]表示状态cur的最后一步是i;
如果为1,代表这个不可行,continue掉;
题目链接:https://www.patest.cn/contests/gplt/L3-015
(怎么弄超链接,我真的不会)
AC代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define test printf("*** ") #define ka getchar();getchar() #define ka1 getchar() using namespace std; typedef long long LL; const int N = 110; const int M = 1000005; const int INF = 0x3f3f3f3f; const LL mod = 1000000007; const double eps=1e-8; int vis[N],ans[N]; int state[1<<21][N];//坑点1,状压处理 set<int> son[N]; char ar[N][N]; int flag,n; void dfs(int u,int t,int cur){ if(flag)return; for(set<int>::iterator p=son[u].begin();p!=son[u].end();++p){ int tmp=*p; if(t==n){ if(tmp==ans[0]){ flag=1; return; } continue; } if(vis[tmp]||state[cur|(1<<tmp)][tmp])continue; vis[tmp]=1; ans[t]=tmp; dfs(tmp,t+1,cur|(1<<tmp)); if(flag)return; state[cur|(1<<tmp)][tmp]=1; vis[tmp]=0; } } int main(){ flag=0; scanf("%d",&n); for(int i=0;i<=n;++i){ son[i].clear(); } for(int i=0;i<n;++i){ scanf("%s",ar[i]); for(int j=0;j<n;++j){ if(ar[i][j]=='W'){ son[i].insert(j); } if(ar[i][j]=='L'){ son[j].insert(i);//坑点2,双循环赛制 } } } memset(vis,0,sizeof(vis)); vis[0]=1; ans[0]=0; dfs(0,1,1); if(flag==0){ printf("No Solution "); return 0; } for(int i=0;i<n;++i){ if(i!=n-1) printf("%d ",ans[i]+1); else printf("%d ",ans[i]+1); } return 0; }
(set遍历元素不是要先:set<int>::iterator 吗;然后我 set<int>::iterator p,把p作为全局变量,然后dfs找bug找一晚上,至于为什么不要设为全局变量,自己试一下就知道了)
(写完csdn再写博客园,真累)