大意略。

思路:求得强连通缩点后,可知是DAG图的最小边覆盖,用二分匹配即可。

 

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
using namespace std;

const int maxn = 5010;
const int maxm = 100100;

struct Edge
{
    int v, next;
}edge[maxm], edge2[maxm];

int xlink[maxn], ylink[maxn];
bool vis[maxn];

int first[maxn], first2[maxn];

int stack[maxn], low[maxn], ins[maxn], dfn[maxn];
int belong[maxn];

int cnt, cnt2;

int scnt, top, tot;

void init()
{
    cnt = cnt2 = 0;
    scnt = top = tot = 0;
    
    memset(first, -1, sizeof(first));
    memset(first2, -1, sizeof(first2));
    memset(xlink, -1, sizeof(xlink));
    memset(ylink, -1, sizeof(ylink));
    
    memset(ins, 0, sizeof(ins));
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
}

int nx, ny;
int n, m, k;

void read_graph(int u, int v)
{
    edge[cnt].v = v;
    edge[cnt].next = first[u], first[u] = cnt++;
}

void read_graph2(int u, int v)
{
    edge2[cnt2].v = v;
    edge2[cnt2].next = first2[u], first2[u] = cnt2++;
}

int dx[maxn], dy[maxn];

const int INF = 0x3f3f3f3f;

int dis;

int bfs()
{  
    queue<int> q;  
    dis = INF;  
    memset(dx, -1, sizeof(dx));  
    memset(dy, -1, sizeof(dy));
    
    for(int i = 1; i <= nx; i++)  
    {  
        if(xlink[i] == -1)  
        {  
            q.push(i);  
            dx[i] = 0;  
        }  
    }
    
    while(!q.empty())  
    {  
        int u = q.front(); q.pop();  
        if(dx[u] > dis) break;  
        for(int e = first2[u]; e != -1; e = edge2[e].next)  
        {  
            int v = edge2[e].v;  
            if(dy[v] == -1)  
            {  
                dy[v] = dx[u] + 1;  
                if(ylink[v] == -1) dis = dy[v];  
                else  
                {  
                    dx[ylink[v]] = dy[v]+1;  
                    q.push(ylink[v]);  
                }  
            }  
        }  
    }  
    return dis != INF;  
}  
  
int find(int u)  
{  
    for(int e = first2[u]; e != -1; e = edge2[e].next)  
    {  
        int v = edge2[e].v;  
        if(!vis[v] && dy[v] == dx[u]+1)
        {  
            vis[v] = 1;  
            if(ylink[v] != -1 && dy[v] == dis) continue;  
            if(ylink[v] == -1 || find(ylink[v]))  
            {
                xlink[u] = v, ylink[v] = u;  
                return 1;  
            }  
        }  
    }  
    return 0;  
}  
  
int MaxMatch()  
{  
    int ans = 0;  
    while(bfs())  
    {  
        memset(vis, 0, sizeof(vis));  
        for(int i = 1; i <= nx; i++) if(xlink[i] == -1)  
        {  
            ans += find(i);  
        }  
    }  
    return ans;  
}  

void dfs(int u)
{
    int v;
    low[u] = dfn[u] = ++tot;
    stack[top++] = u, ins[u] = 1;
    for(int e = first[u]; e != -1; e = edge[e].next)
    {
        v = edge[e].v;
        if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); }
        else if(ins[v]) { low[u] = min(low[u], dfn[v]); }
    }
    if(low[u] == dfn[u])
    {
        scnt++;
        do { v = stack[--top]; belong[v] = scnt; ins[v] = 0; } while(u != v);
    }
}

void Tarjan()
{
    for(int v = 1; v <= n; v++) if(!dfn[v])
        dfs(v);
}

inline void readint(int &x)
{
    char c = getchar();
    while(!isdigit(c)) c = getchar();
    
    x = 0;
    while(isdigit(c))
    {
        x = x*10 + c-'0';
        c = getchar();
    }
}

inline void writeint(int x)
{
    if(x > 9) writeint(x/10);
    putchar(x%10+'0');
}

void read_case()
{
    init();
    readint(n), readint(m);
    
    while(m--)
    {
        int u, v;
        readint(u), readint(v);
        read_graph(u, v);
    }
}

void build()
{
    Tarjan();
    nx = ny = scnt;
    for(int u = 1; u <= n; u++)
    {
        for(int e = first[u]; e != -1; e = edge[e].next)
        {
            int v = edge[e].v;
            if(belong[u] != belong[v]) read_graph2(belong[u], belong[v]);
        }
    }
}

void solve()
{
    read_case();
    build();
    
    int ans = MaxMatch();
    
    writeint(nx-ans), puts("");
}

int main()
{
    int T;
    readint(T);
    while(T--)
    {
        solve();
    }
    return 0;
}
View Code

 

 

 

posted on 2013-05-28 10:42  Buck Meister  阅读(127)  评论(0编辑  收藏  举报