您的位置:首页 > 其它

hdu 4685 Prince and Princess (2013.8.15 多校8---1010)

2013-08-17 14:31 375 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4685

先找最大匹配数ret

然后把将n这一边的大于n的m-ret与m这一边的n+m-ret边连起来,将n这一边的n+m-ret与m这一边的大于m的n-ret连起来,做最大匹配,得到一个匹配

然后根据这个匹配找强连通分量,属于同一强连通分量的priceness和price可以任意配

同一强连通分量的所有priceness可以给同一强连通分量的price。

用hopcroft-karp算法890ms,用匈牙利算法2656ms。。。

顺便在代码中附上hopcroft-karp算法和找强连通分量的模板~

/**
*先找最大匹配ret
*然后把将n和m以上的n+m-ret边连起来做最大匹配
*然后按这个匹配找强连通分量,属于同一强连通分量的priceness和price可以任意配
*
*@Author: xiaohai---xysmlx
*/
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<set>
#include<list>
#include<map>
#include<iterator>
#include<cstdlib>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#include<functional>
using namespace std;
typedef long long LL;
#define ROUND(x) round(x)
#define FLOOR(x) floor(x)
#define CEIL(x) ceil(x)
const int maxn=1010;
const int maxm=maxn*maxn;
const int inf=0x3f3f3f3f;
const LL inf64=0x3f3f3f3f3f3f3f3fLL;
const double INF=1e30;
const double eps=1e-6;

/**
*大数据二分图匹配:Hopcroft-Karp($O(\sqrt{V}E)$)
*适用于数据较大的二分匹配(从0到n-1)
*输入:Nx,Ny,g[][]
*输出:res=MaxMatch();
*/
int g[maxn][maxn],Mx[maxn],My[maxn],Nx,Ny;
int dx[maxn],dy[maxn],dis;
bool vst[maxn];
int res;
bool searchP()
{
queue<int>Q;
dis=inf;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=0; i<Nx; i++)
if(Mx[i]==-1)
{
Q.push(i);
dx[i]=0;
}
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(dx[u]>dis)  break;
for(int v=0; v<Ny; v++)
if(g[u][v]&&dy[v]==-1)
{
dy[v]=dx[u]+1;
if(My[v]==-1)  dis=dy[v];
else
{
dx[My[v]]=dy[v]+1;
Q.push(My[v]);
}
}
}
return dis!=inf;
}
bool DFS(int u)
{
for(int v=0; v<Ny; v++)
if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1)
{
vst[v]=1;
if(My[v]!=-1&&dy[v]==dis) continue;
if(My[v]==-1||DFS(My[v]))
{
My[v]=u;
Mx[u]=v;
return 1;
}
}
return 0;
}
int MaxMatch()
{
int res=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(searchP())
{
memset(vst,0,sizeof(vst));
for(int i=0; i<Nx; i++)
if(Mx[i]==-1&&DFS(i))  res++;
}
return res;
}

/**
*有向图强连通分量:Tarjan算法($O(V+E)$)
*输入:图(从0到n-1)
*输出:sid[](强连通分量标号)
*/
//const int maxn=0;
//const int maxm=0;
struct Edge
{
int v,w;
int next;
} edge[maxm];
int head[maxn],edgeNum;
void addSubEdge(int u,int v)
{
edge[edgeNum].v=v;
edge[edgeNum].next=head[u];
head[u]=edgeNum++;
}
void addEdge(int u,int v)
{
addSubEdge(u,v);
addSubEdge(v,u);
}
int sid[maxn];
int mark[maxn],low[maxn];
int check[maxn];
int sstack[maxn],top;
int dfn,ssn;
int n,m;
void dfs(int k)
{
int i,j;
check[k]=1;
low[k]=mark[k]=dfn++;
sstack[top++]=k;
for(int i=head[k]; i!=-1; i=edge[i].next)
{
int j=edge[i].v;
if(mark[j]==0)
{
dfs(j);
low[k]=min(low[k],low[j]);
}
else if(check[j])
low[k]=min(low[k],mark[j]);
}
if(mark[k]==low[k])
{
while(sstack[--top]!=k)
{
check[sstack[top]]=0;
sid[sstack[top]]=ssn;
}
sid[k]=ssn;
check[k]=0;
++ssn;
}
return;
}
void tarjan()
{
ssn=1;
dfn=1;
top=0;
memset(check,0,sizeof(check));
memset(mark,0,sizeof(mark));
for(int i=0; i<n; ++i) if(mark[i]==0) dfs(i);
}

int N,M;
void init()
{
memset(g,0,sizeof(g));
memset(head,-1,sizeof(head));
edgeNum=0;
}
void input()
{
scanf("%d%d",&N,&M);
Nx=N;
Ny=M;
for(int i=0; i<Nx; i++)
{
int k;
scanf("%d",&k);
while(k--)
{
int x;
scanf("%d",&x);
g[i][x-1]=1;
}
}
}
void solve()
{
res=MaxMatch();
//    cout<<res<<endl;
Nx=Ny=N+M-res;
for(int i=N; i<Nx; i++)
{
for(int j=0; j<Ny; j++)
{
g[i][j]=1;
}
}
for(int i=0; i<Nx; i++)
{
for(int j=M; j<Ny; j++)
{
g[i][j]=1;
}
}
res=MaxMatch();
//    cout<<res<<endl;
//    for(int i=0; i<Nx; i++) cout<<Mx[i]<<" ";
//    cout<<endl;

for(int i=0; i<Nx; i++)
{
for(int j=0; j<Ny; j++)
{
if(g[i][j]&&j!=Mx[i])
{
addSubEdge(Mx[i],j);
}
}
}
n=Ny;
tarjan();
//    for(int i=0;i<n;i++) cout<<sid[i]<<" ";
//    cout<<endl;
}
int main()
{
//    freopen("in.cpp","r",stdin);
int T;
scanf("%d",&T);
for(int kase=1; kase<=T; kase++)
{
init();
input();
solve();

printf("Case #%d:\n",kase);
vector<int> ans;
for(int i=0; i<N; i++)
{
ans.clear();
for(int j=0; j<M; j++)
{
if(g[i][j]&&sid[Mx[i]]==sid[j])
{
ans.push_back(j+1);
}
}
printf("%d",ans.size());
for(int i=0; i<ans.size(); i++)
{
printf(" %d",ans[i]);
}
puts("");
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: