AT_abc199_d题解
前言:
这题是学校模拟赛出的题,开始的时候没有头绪,后来在讲评之后也是恍然大悟了。临近 noip,写篇题解希望 rp++,预祝大家考的都会。
思路:
这题一看数据量就知道肯定是爆搜或者状压了,但是显然不满足无后效性(还是我太蒻了?),所以直接写爆搜。将图分为几个连通互相没有边的图,分开处理,最后答案相乘即可。
易错
爆搜相信大家都会,我在下面写一些易错点:
- 这个图不一定是树,当图中有环时,需要标记,否则答案就会加两遍(or 更多),样例一就是这种情况。
- 一个点的颜色需要先与父亲判断,重复就要跳过,否则计算量过大,喜提 TLE。
- 记得开 long long,否则样例 4 就可以卡掉。
code
#include<iostream> #include<cmath> #include<iomanip> #include<cstdio> #include<string> #include<deque> #include<stack> #include<queue> #include<vector> #include<stdio.h> //#include<map> #include<string.h> #include<time.h> #include<stdlib.h> #include<bitset> using namespace std; int n,m; vector<int> w[25];//图 long long ans[25],tot;//答案 bool vis[25];//是否搜过 int huan[25][25];//有没有环 int c[25]; int work(int x,int fa){ int an=0; vis[x]=1; if(c[x]){//重复搜到肯定是因为有环。 huan[x][fa]=1;//这个环肯定包括这个点和他的两个儿子,一个儿子搜过了,只需要再特判另一个即可。 return c[x]!=c[fa]; } for(int i=1;i<=3;i++){ if(i==c[fa])continue;//易错点2。 c[x]=i; int book=1; memset(huan[x],0,sizeof(huan[x])); //初始化也是易错。 for(int j=0;j<w[x].size();j++){ int v=w[x][j]; if(!huan[x][v])book*=work(v,x);//没有环或环还没搜。 } c[x]=0; an+=book; } return an; } int main(){ cin>>n>>m; for(int i=1;i<=m;i++){ int u,v; cin>>u>>v; w[u].push_back(v); w[v].push_back(u); } for(int i=1;i<=n;i++){ if(!vis[i]){ vis[i]=1; ans[++tot]=work(i,0); } } for(int i=2;i<=tot;i++)ans[i]*=ans[i-1]; cout<<ans[tot]; return 0; }