【强连通】 HDU 4685 Prince and Princess

来源:互联网 发布:蓝桥物流软件下载 编辑:程序博客网 时间:2024/05/21 15:46

点击打开链接

题意:n个王子,m个公主,配对。每个王子可以在给出的ki个公主中选一个结婚。。

求最大的配对情况下,配对的状态。

题解:最后的answer 肯定是一些公主之间的连通的状态。

二分匹配找到与王子配对的公主。

再对公主对应的王子对应的ki个公主建边,形成的连通图既是对应某个王子的能取的公主

#pragma comment(linker, "/STACK:1024000000,1024000000")#include <cstdio>#include <cstring>#include <cstdlib>#include <string>#include <iostream>#include <algorithm>#include <sstream>#include <cmath>using namespace std;#include <queue>#include <stack>#include <vector>#include <deque>#include <set>#include <map>#define cler(arr, val)    memset(arr, val, sizeof(arr))#define FOR(i,a,b)  for(int i=a;i<=b;i++)#define IN   freopen ("in.txt" , "r" , stdin);#define OUT  freopen ("out.txt" , "w" , stdout);typedef long long  LL;const int MAXN = 1011;const int MAXM = 610;const int INF = 0x3f3f3f3f;const LL mod = 2147483647;const double eps= 1e-8;const double pi=acos(-1.0);#define lson l,m, rt<<1#define rson m+1,r,rt<<1|1const int N = 21001;const int M = 200010;int n, m;//n m 为点数和边数struct Edge{    int from, to, nex;    bool sign;//是否为桥}edge[M];int head[N], edgenum;void add(int u, int v){//边的起点和终点    Edge E={u, v, head[u], false};    edge[edgenum] = E;    head[u] = edgenum++;}int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)int taj;//连通分支标号,从1开始int Belong[N];//Belong[i] 表示i点属于的连通分支int bridge;bool Instack[N];vector<int> bcc[N]; //标号从1开始void tarjan(int u ,int fa){    DFN[u] = Low[u] = ++ Time ;    Stack[top ++ ] = u ;    Instack[u] = 1 ;    for (int i = head[u] ; ~i ; i = edge[i].nex )    {        int v = edge[i].to;        if(DFN[v] == -1)        {            tarjan(v , u);            Low[u] = min(Low[u] ,Low[v]) ;            if(DFN[u] < Low[v])            {                edge[i].sign =edge[i^1].sign = 1;//为割桥            }        }        else if(Instack[v])        {            Low[u] = min(Low[u] ,DFN[v]) ;        }    }    if(Low[u] == DFN[u])    {        int now;        taj ++ ;        bcc[taj].clear();        do{            now = Stack[-- top] ;            Instack[now] = 0 ;            Belong [now] = taj ;            bcc[taj].push_back(now);        }while(now != u) ;    }}void tarjan_init(int all){    memset(DFN, -1, sizeof(DFN));    memset(Instack, 0, sizeof(Instack));    top = Time = taj = 0;    for(int i=1;i<=all;i++)        if(DFN[i]==-1 )            tarjan(i, -1); //注意开始点标!!!}vector<int>G[N];int uN,vN;//u,v数目int g[MAXN][MAXN];int linker[MAXN],link[MAXN];bool used[MAXN];bool dfs(int u)//从左边开始找增广路径{    int v;    for(v=1;v<=vN;v++)//这个顶点编号从0开始,若要从1开始需要修改      if(g[u][v]&&!used[v])      {          used[v]=true;          if(linker[v]==-1||dfs(linker[v]))          {//找增广路,反向              linker[v]=u;              link[u]=v;              return true;          }      }    return false;//这个不要忘了,经常忘记这句}int hungary(){    int res=0;    int u;    memset(linker,-1,sizeof(linker));    memset(link,-1,sizeof(link));    for(u=1;u<=uN;u++)    {        memset(used,0,sizeof(used));        if(dfs(u)) res++;    }    return res;}void init(){    memset(head, -1, sizeof(head));    edgenum=0;    cler(g,0);}int main(){    int cas=1,t;    cin>>t;    while(t--)    {        scanf("%d%d",&n,&m);        init();        int a,b,x;        for(int i=1;i<=n;i++)        {            scanf("%d",&x);            for(int j=0;j<x;j++)            {                scanf("%d",&a);                g[i][a]=1;            }        }        uN=n,vN=m;        x=hungary();        int num=n+m-x;        for(int i=n+1;i<=num;i++)            for(int j=1;j<=num;j++)                 g[i][j]=1;        for(int i=m+1;i<=num;i++)            for(int j=1;j<=num;j++)                 g[j][i]=1;        uN=vN=num;        hungary();        for(int i=1;i<=num;i++)        {            for(int j=1;j<=num;j++)            {                if(link[i]!=j&&g[i][j])                    add(link[i],j);            }        }        tarjan_init(num);        for(int i = 0; i <=n; i++)            G[i].clear();       for(int i=1;i<=n;i++)            for(int j=1;j<=m;j++)                if(g[i][j]&&Belong[link[i]]==Belong[j])                    G[i].push_back(j);        printf("Case #%d:\n",cas++);        for(int i=1;i<=n;i++)        {            printf("%d",G[i].size());            for(int j=0;j<G[i].size();j++)                printf(" %d",G[i][j]);            puts("");        }    }    return 0;}


0 0
原创粉丝点击