HDU6165 FFF at Valentine(并查集+tarjan缩点+拓扑排序)
2017-08-23 00:02
411 查看
题目:
<—传送门
思路:刚开始用bfs,dfs暴搜T了n发,然后换了个思路用拓扑排序做然后又wa了n发。。。看了官方题解才想到思路有漏洞,顺便学了新姿势缩点。主要是判断两个点之间是否有路径,如果拓扑排序当前层存在两个及以上入度为0的点,那么这些点一定不存在通路。直接拓扑的话会碰到强联通子图,所以要把强联通子图都缩成一个点,然后新建一张图,跑一遍拓扑排序判断一下,就能得出答案。多加了一个并查集判断给的图是不是连通图,不是的话直接Light my fire!,就不用做后面的了。
下面是代码:
<—传送门
思路:刚开始用bfs,dfs暴搜T了n发,然后换了个思路用拓扑排序做然后又wa了n发。。。看了官方题解才想到思路有漏洞,顺便学了新姿势缩点。主要是判断两个点之间是否有路径,如果拓扑排序当前层存在两个及以上入度为0的点,那么这些点一定不存在通路。直接拓扑的话会碰到强联通子图,所以要把强联通子图都缩成一个点,然后新建一张图,跑一遍拓扑排序判断一下,就能得出答案。多加了一个并查集判断给的图是不是连通图,不是的话直接Light my fire!,就不用做后面的了。
下面是代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<set> #include<stack> #include<vector> #include<algorithm> #define N 1010 #define INF 0x3f3f3f3f #define LL long long #define EPS 1e-8 using namespace std; struct point{ int num,k; friend bool operator< (point a,point b) { return a.num<b.num; } }p ; vector<int> g ; //旧图 set<int> g_new ; //新图 int n,m,xb ; int pa ; int dfn ,low ,tot,cnt; bool vis ; stack<int> s; void tarjan(int u) { dfn[u]=low[u]=++tot; s.push(u); vis[u]=true; for(int i=0;i<g[u].size();i++) { int &tmp=g[u][i]; if(!dfn[tmp]) { tarjan(tmp); low[u]=min(low[u],low[tmp]); } else if(vis[tmp]) { low[u]=min(low[u],dfn[tmp]); } } if(low[u]==dfn[u]) //缩点 { cnt++; int tmp; do{ tmp=s.top(); vis[tmp]=false; s.pop(); pa[tmp]=cnt; }while(tmp!=u); } } void init() //初始化 { for(int i=1;i<=n;i++) { pa[i]=i; p[i].num=0,p[i].k=i; } cnt=tot=0; memset(vis,false,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); } void clear_g() //删除建的边 { for(int b30f i=1;i<=n;i++) g[i].clear(); for(int i=1;i<=cnt;i++) g_new[i].clear(); } int findset(int v) { int t1,t2=v; while(v!=pa[v]) v=pa[v]; while(t2!=pa[t2]) { t1=pa[t2]; pa[t2]=v; t2=t1; } return v; } void union_nodes(int a, int b) { int a1=findset(a); int b1=findset(b); if(a1!=b1) { pa[a1]=b1; } } bool sol() //拓扑排序得出答案 { int k=1; while(k<=cnt) { sort(p+k,p+cnt+1); //cout<<p[k].k<<endl; if(p[k].num>0) return true; if(k<cnt&&p[k].num==p[k+1].num) return false; for(int i=k+1;i<=cnt;i++) xb[p[i].k]=i; p[k].num=-1; for(set<int>::iterator it=g_new[p[k].k].begin();it!=g_new[p[k].k].end();it++) { p[xb[*it]].num--; } k++; } return true; } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); init(); int u,v; for(int i=0;i<m;i++) { scanf("%d%d",&u,&v); union_nodes(u,v); g[u].push_back(v); } bool flag=true; for(int i=1;i<=n;i++) //并查集判断是否为连通图 { if(findset(i)!=findset(1)) { flag=false; break; } } if(!flag) { printf("Light my fire!\n"); clear_g(); continue; } for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } //cout<<cnt<<endl; for(int i=1;i<=n;i++) //建新图 { //cout<<pa[i]<<endl; for(int j=0;j<g[i].size();j++) { int &tmp=g[i][j]; if(pa[tmp]!=pa[i]) g_new[pa[i]].insert(pa[tmp]); } } for(int i=1;i<=cnt;i++) //计算入度 { //cout<<i<<' '<<g_new[i].size()<<endl; for(set<int>::iterator it=g_new[i].begin();it!=g_new[i].end();it++) { p[*it].num++; //cout<<*it<<endl; } } /*for(int i=1;i<=cnt;i++) cout<<p[i].k<<' '<<p[i].num<<endl;*/ if(sol()) printf("I love you my love and our love save us!\n"); else printf("Light my fire!\n"); clear_g(); } }
相关文章推荐
- HDU6165 FFF at Valentine(深搜dfs,2017 HDU多校联赛 第9场)
- HDU6165 FFF at Valentine【BFS】
- hdu6165-tarjan&&多校9&&模板修正|XJB暴力-FFF at Valentine
- HDU6165 FFF at Valentine(深搜dfs,2017 HDU多校联赛 第9场)
- hdu6165 FFF at Valentine【强联通缩点+拓扑排序】
- HDU6165-FFF at Valentine
- hdu6165 FFF at Valentine 强联通分量+拓扑排序
- HDU6165-FFF at Valentine
- HDU6165 FFF at Valentine(爆搜)
- hdu6165 FFF at Valentine 2017多校第九场1005 dfs
- HDU 6165 FFF at Valentine
- 2017 Multi-University Training Contest - Team 9 1005&&HDU 6165 FFF at Valentine【强联通缩点+拓扑排序】
- hdu 6165 FFF at Valentine(强连通分量缩点+拓扑排序)
- hdu 6165 FFF at Valentine(强连通分量缩点+拓扑排序)
- HDU-2017 多校训练赛9-1005-FFF at Valentine
- 文章标题 HDU 6165: FFF at Valentine(强连通分量缩点)
- hdu 6165 FFF at Valentine (Tarjan算法,scc+dp)
- hdu 6165 FFF at Valentine(强连通分量缩点+拓扑排序)
- hdu 6165 FFF at Valentine(强连通分量缩点+拓扑排序)
- hdu 6165 FFF at Valentine(强连通分量缩点+拓扑排序)