HDU 2767
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2767
题意:
给n个命题,m个推导式表示A能推出B。问至少还需要多少个推导式能使所有命题等价。
思路:
强连通没什么好说的,主要是最后的答案应该输出什么。
n-缩点最长链点数。这个很明显有问题。
然后想到最后形成一个森林,所以就是叶子节点数+根节点数-1。然而只差一点点了。
题解是gmax(叶子节点数,根节点数),特判全图强连通的情况。
突然想到之前看到的一句话。
做什么图论,做了也和没做一样。
源码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
#define gmin(a,b) ((a) < (b) ? (a) : (b))
#define gmax(a,b) ((a) > (b) ? (a) : (b))
const int MAXN = 20000 + 5;
int pre[MAXN], low[MAXN], dfs_clock;
int sccno[MAXN], scc_cnt, num[MAXN];
int n, m;
vector<int>lin[MAXN], lv[MAXN];
stack<int>sta;
queue<int>que;
int ans;
int in[MAXN], out[MAXN], val[MAXN];
int vis[MAXN];
void dfs_scc(int u)
{
pre[u] = low[u] = ++dfs_clock;
sta.push(u);
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i];
if(!pre[v]){
dfs_scc(v);
low[u] = gmin(low[u], low[v]);
}
else if(!sccno[v])
low[u] = gmin(low[u], pre[v]);
}
if(low[u] == pre[u]){
scc_cnt++;
while(!sta.empty()){
int org = sta.top(); sta.pop();
sccno[org] = scc_cnt;
num[scc_cnt]++;
if(org == u)
break;
}
}
}
void Tarjan()
{
memset(pre, 0, sizeof(pre));
dfs_clock = 0;
memset(sccno, 0, sizeof(sccno));
memset(num, 0, sizeof(num));
scc_cnt = 0;
while(!sta.empty()) sta.pop();
ans = 0;
for(int i = 1 ; i <= n ; i++)
if(pre[i] == 0) dfs_scc(i);
}
void topo()
{
for(int i = 1 ; i <= n ; i++){
for(int j = 0 ; j < (int)lin[i].size() ; j++){
int u = i, v = lin[i][j];
if(sccno[u] != sccno[v]){
in[sccno[v]]++;
out[sccno[u]]++;
}
}
}
// memset(vis, 0, sizeof(vis));
// for(int i = 1 ; i <= scc_cnt ; i++)
// if(in[i] == 0) que.push(i);
// while(!que.empty()){
// int org = que.front(); que.pop();
// for(int i = 0 ; i < (int)lv[org].size() ; i++){
// int v = lv[org][i];
// in[v]--;
// val[v] = gmax(val[v], val[org] + num[org]);
// if(in[v] == 0) que.push(v);
// }
//
// }
}
int main()
{
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
for(int i = 1 ; i <= n ; i++)
lin[i].clear();
int u, v;
for(int i = 1 ; i <= m ; i++){
scanf("%d%d", &u, &v);
lin[u].push_back(v);
}
Tarjan();
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
memset(val, 0, sizeof(val));
topo();
// printf("scc_cnt = %d\n", scc_cnt);
// for(int i = 1 ; i <= scc_cnt ; i++)
// printf("val[%d] = %d\n", i, val[i]);
// for(int i = 1 ; i <= n ; i++)
// printf("sccno[%d] = %d\n", i, sccno[i]);
// for(int i = 1 ; i <= scc_cnt ; i++)
// printf("num[%d] = %d\n", i, num[i]);
int t1, t2;
t1 = t2 = 0;
for(int i = 1 ; i <= scc_cnt ; i++){
if(in[i] == 0) t1++;
if(out[i] == 0) t2++;
}
// for(int i = 1 ; i <= scc_cnt ; i++)
// ans = gmax(ans, val[i] + num[i]);
if(scc_cnt == 1)
printf("0\n");
else
printf("%d\n", gmax(t1, t2));
}
return 0;
}
/*
4 4
1 3
3 2
2 4
1 4
*/