HDU6165 FFF at Valentine(并查集+tarjan缩点+拓扑排序)
来源:互联网 发布:金元证券软件下载 编辑:程序博客网 时间:2024/06/09 22:58
题目: <—传送门
思路:刚开始用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-8using namespace std;struct point{ int num,k; friend bool operator< (point a,point b) { return a.num<b.num; }}p[N];vector<int> g[N]; //旧图set<int> g_new[N]; //新图int n,m,xb[N];int pa[N];int dfn[N],low[N],tot,cnt;bool vis[N];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 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(); }}
阅读全文
0 0
- HDU6165 FFF at Valentine(并查集+tarjan缩点+拓扑排序)
- hdu6165 FFF at Valentine【强联通缩点+拓扑排序】
- hdu 6165 FFF at Valentine(tarjan缩点+拓扑排序)
- HDU 6165 FFF at Valentine(tarjan缩点+拓扑排序)
- hdu6165 FFF at Valentine 强联通分量+拓扑排序
- hdu6165 FFF at Valentine 强联通缩点
- HDU 6165 FFF at Valentine (tarjan缩点+拓扑判任意两点联通)
- HDU6165-FFF at Valentine
- HDU6165-FFF at Valentine
- 2017年多校赛第九场 1005 FFF at Valentine(缩点+拓扑排序)
- hdu 6165 FFF at Valentine(强连通分量缩点+拓扑排序)
- hdu 6165 FFF at Valentine(强连通分量缩点+拓扑排序)
- HDU6165 FFF at Valentine【BFS】
- HDU6165 FFF at Valentine(爆搜)
- hdu6165-tarjan&&多校9&&模板修正|XJB暴力-FFF at Valentine
- 2017多校九 05题 hdu 6165 FFF at Valentine 缩点 dp找最长链/拓扑排序
- hdu6165 (缩点+拓扑排序)
- HDU --- 6165 FFF at Valentine 多校第九场 【强联通缩点 + 维护拓扑序】
- LSPCI命令打印出PCI总线上连接的所有设备
- 现在谈谈Vue 里面的computed 属性
- javascript数据结构系列(四)-队列
- 使用gdb调试多线程多进程程序
- AtomicInteger 类的理解与使用
- HDU6165 FFF at Valentine(并查集+tarjan缩点+拓扑排序)
- msyql 查看行锁情状况
- 【Spark2.0源码学习】-3.Endpoint模型介绍
- 这么多开源框架,该用哪个好?
- 组合模式
- Linux基本操作命令
- 【MVP】AppManager一些有关Activity和程序退出的操作
- python struct笔记
- 10023---分布式系统理论基础