猪猪的想法
输入文件:thought.in
输出文件:thought.out
时间限制:1 second
空间限制:128 MB
题目描述
狗蛋养了许多只可爱的猪猪,这些猪猪她萌都有一些奇怪的想法:比如说猪猪喜欢猪猪,猪猪之间的喜欢是一
个很有趣的事情——喜欢是可以传递的,例如猪猪A喜欢猪猪B,猪猪B喜欢猪猪C,那么可以说猪猪A喜欢猪猪C
。有意思的一点是,她萌不喜欢自恋的猪猪,一旦出现了自恋的猪猪,那么极有可能的是这个团体出现危险。现在
给你只猪猪对单方面的关系,请问这个只猪猪组成的团体是否危险呢?是输出Yes ,否输出No 。
输入格式
题目包含多组数据
第一行一个数T,表示数据组数。
对于每一组数据:
第一行两个正整数n,m,表示有n只猪猪和m个单向关系。
接下来行,每一行两个数表示的单向关系。
输出格式
共T行,每一行一个字母,表示结果。
样例
样例输入
2
2 2
1 2
2 1
2 1
1 2
样例输出
No
Yes
数据范围
n <=10^6 , m <= n*(n-1)/2 ;
题解:用拓扑看有没有环就好了,不过我用的tarjian,不过此题的一个点 指向自己的情况要注意
#include<iostream> #include<cstdio> #include<cstdlib> #include<vector> #include<cstring> using namespace std; const int maxn = 100000 + 5; int n, m, top, t[maxn], dfn[maxn], low[maxn], cnt, idx, scccnt; bool ins[maxn]; vector <int> G[maxn], scc[maxn]; void tarjian(int u){ dfn[u] = low[u] = ++idx; t[++top] = u; ins[u] = 1; for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(!dfn[v]){ tarjian(v); low[u] = min(low[v], low[u]); } else if(ins[v])low[u] = min(low[u], dfn[v]); } if(dfn[u] == low[u]){ int x = dfn[u]; scccnt++; while(1){ scc[scccnt].push_back(t[top]); ins[t[top--]] = 0;
if(t[top+1]])break; } } } int main(){ freopen("thought.in","r",stdin); freopen("thought.out","w",stdout); int Q; scanf("%d",&Q); while(Q--){ memset(t, 0, sizeof(t)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(ins, 0, sizeof(ins)); top = idx = scccnt = cnt = 0; scanf("%d%d",&n,&m); for(int i = 1; i <= n + 1; i++) G[i].clear(), scc[i].clear(); for(int i = 1; i <= m; i++){ int u, v; scanf("%d%d",&u,&v); G[u].push_back(v); } for(int i = 1; i <= n; i++) if(!dfn[i])tarjian(i); for(int i = 1; i <= scccnt; i++){ if(scc[i].size() != 1)cnt++; } if(cnt)cout<<"Yes"<<endl; else cout<<"No"<<endl; } return 0; }
最长的路径
输入文件:dag.in
输出文件:dag.out
时间限制:1 second
空间限制:128 MB
题目描述
给定一张个点条边的有向无环图,每个点有点权,问从出发,路径最长是多少。
此处路径长度的定义为路径上的经过的点的点权和(包括起点和终点)。
输入格式
第一行包含n,m两个数。
接下来一行个数,第i个数表示的点权wi。
接下来行,每一行两个数表示的一条单向边。
输出格式
输出最长路径的长度。
样例
样例输入
5 5
1 2 3 4 5
1 2
2 3
3 4
4 5
5 1
样例输出
15
数据范围
n <=10^5 , m <= n*(n-1)/2 ;
题解:SPFA,用dijsktra要存负权,不能跑最大路
#include<iostream> #include<cstdio> #include<cstdlib> #include<vector> #include<queue> #include<cstring> #define maxn 1000000 +5 using namespace std; int n, m, S; struct edge{ int to,co; }; vector <edge> G[maxn]; int dis[maxn], w[maxn], ans; bool inq[maxn]; queue <int> Q; void SPFA(int s){ dis[s] = w[s]; inq[s] = 1; Q.push(s); while(!Q.empty()){ int u = Q.front(); Q.pop(); inq[u] = 0; for(int i = 0; i < G[u].size(); i++){ edge &e = G[u][i]; if(dis[e.to] < dis[u] + e.co){ dis[e.to] = dis[u] + e.co; if(!inq[e.to]){ Q.push(e.to); inq[e.to] = 1; } } } } } int main(){ freopen("dag.in","r",stdin); freopen("dag.out","w",stdout); cin>>n>>m>>S; for(int i = 1; i <= n; i++) scanf("%d",&w[i]); for(int i = 1; i <= m; i++){ int u, v; scanf("%d%d",&u,&v); G[u].push_back((edge){v,w[v]}); } SPFA(S); for(int i = 1; i <= n; i++) ans = max(ans, dis[i]); cout<<ans<<endl; }
美丽的有向图
输入文件:beauty.in
输出文件:beauty.out
时间限制:1 second
空间限制:128 MB
题目描述
定义一张有向图是美丽的,当且仅当任意选出两点:要么可以到,要么可以到.
给定一张个点条边的有向图,判断是否是美的。如果是,输出I am beautiful! ,否则输出Go away Anna.
输入格式
题目包含多组数据。
第一行一个数,表示数据组数。
对于每一组数据:
第一行n,m两个正整数,表示有n只猪猪和m个单向关系。
接下来行,每一行两个数表示的单向关系。
输出格式
共行,每一行一个字符串,表示结果。
样例
样例输入
2
3 3
1 2
2 3
3 1
5 5
1 2
2 3
2 4
3 5
4 5
样例输出
I am beautiful!
Go away Anna.
数据范围
n <=10^5 , m <= n*(n-1)/2 ;
题解:先tarjian缩点,拓扑时有出度为2的点就不行了;缩点有点问题,就贴一个标答
#include <bits/stdc++.h> using namespace std; const int maxn = 200005; int dfn[maxn];//dfs顺序 int low[maxn]; int index1;//记录时间的标号 bool state[maxn];//是否在栈里. stack<int>s; vector<int>G[maxn]; vector<int>g[maxn]; int cnt[maxn]; int num[maxn], du[maxn];//num数组不一定要,各个强连通分量包含点的个数,数组编号1~cnt int scc,flag;//scc为强连通分量的个数 int vis[maxn]; void init() { scc = 0,flag=0; memset(du, 0, sizeof(du)); memset(state, false, sizeof(state)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(cnt, 0, sizeof(cnt)); memset(vis, false, sizeof(vis)); memset(num, 0, sizeof(num)); while(!s.empty()) s.pop(); for(int i = 0; i < maxn; i++) { G[i].clear(); g[i].clear(); } } void tarjan(int u)//tarjan 处理强连通分量。 { dfn[u] = low[u] = ++index1; s.push(u); state[u] = true; vis[u] = true; for(int i = 0; i < G[u].size(); i++) { int w = G[u][i]; if(!vis[w]) { tarjan(w); low[u] = min(low[w], low[u]); } else if(state[w]) { low[u] = min(low[u], dfn[w]); } } if(low[u] == dfn[u]) { scc++; for(;;) { int x = s.top(); s.pop(); cnt[x] = scc;//标记v点属于哪个强连通分量 num[scc]++;//记录这个强连通分量有多少个点组成 state[x] = false; if(x == u)break; } } } queue<int>q; void topsort() { while (q.size()) q.pop(); int sizz=0; for(int i=1;i<=scc;i++) { if(!du[i]) { sizz++; q.push(i); } } if(sizz>=2) flag=1;//如果刚缩点后就有两个以上度为0的坑定不可以啊 while(!q.empty()&&!flag)//拓扑找出度为2的点 { int u=q.front(); q.pop(); int siz=0; for(int i=0;i<g[u].size()&&!flag;i++) { int to=g[u][i]; du[to]--; if(du[to]==0) { siz++; q.push(to); } } if(siz>=2) flag=1; } } int main() { // freopen ( "beauty8.in", "r", stdin ) ; int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); init(); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); } for(int i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } for(int i=1;i<=n;i++)//新建图 { int u=cnt[i]; for(int j=0;j<G[i].size();j++) { int v=cnt[G[i][j]]; if(u!=v) { g[u].push_back(v); du[v]++;//入度 } } } topsort(); puts ( flag ? "Go away Anna." : "I am beautiful!" ) ; } return 0; }