POJ-1904 King's Quest

题目:

http://poj.org/problem?id=1904

题意:

每个王子都有喜欢的妹子,给出了其中一种匹配方案,要求出每个王子能够娶的所有人,当王子娶这些妹子中的一个时其他王子都有能够娶到的喜欢的妹子。

思路:

这道题的想法很精妙,因为给出了其中一个匹配方案,所以可以通过搜其他可以交换的方案,也就是在同一个强联通分量的点可以互相交换,也就可以被其中的所有王子娶。

也就从一道二分图匹配题改成了求最大连通分量的题,隐藏的很深,通常很容易当成二分图一直做下去。

另外学到了输入输出外挂,真的很有用。

代码:

#define N 112345

int flag,sum,ave,ans,res,len,ans1,ans2;
int a[N];
vector<int>g[N];
int dfn[N];
int low[N];
stack<int>st;
int inStack[N];
int belong[N];
int index,cnt;
int n,m;

void init()
{
    while(!st.empty())st.pop();
	memset(dfn, -1, sizeof(dfn));
	memset(low, 0, sizeof(low));
	memset(inStack, 0, sizeof(inStack));
	index = cnt = 1;
}

void tarjan(int x)
{
	int i, a;
	low[x] = dfn[x] = index;
	index++;
	st.push(x);
	inStack[x] = 1;
	int len = g[x].size();
	for(i=0;i<len;i++)
	{
	    int t=g[x][i];
		if(dfn[t] == -1)
		{
			tarjan(t);
			low[x] = min(low[x], low[t]);
		}
		else if(inStack[t])
			low[x] = min(low[x], dfn[t]);
	}

	if(low[x] == dfn[x])
	{
		int temp;
		while(!st.empty())
		{
			temp = st.top();
			st.pop();
			belong[temp] = cnt;
		 	inStack[temp] = 0;
		 	if(temp == x)
		 		break;
		}
		cnt++;
	}
}

void solve()
{
	int i, j;
    init();
    for(i = 1; i <= n; i++)
        if(dfn[i] == -1)
            tarjan(i);
}
int Scan()
{
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}
void Out(int a)
{
    if(a>9)
        Out(a/10);
    putchar(a%10+'0');
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d",&n)!=EOF&&n)
    {
        for(i=0;i<=2*n;i++)
            g[i].clear();
        for(i=1;i<=n;i++)
        {
            m=Scan();
            for(j=0;j<m;j++)
            {
                t=Scan();
                g[i].push_back(t+n);
            }
        }
        for(i=1;i<=n;i++)
        {
            t=Scan();
            g[t+n].push_back(i);
        }
        solve();
        for(i=1;i<=n;i++)
        {
            x=g[i].size();m=0;
            for(j=0;j<x;j++)
            {
                if(belong[i]==belong[g[i][j]])
                    a[m++]=g[i][j]-n;
            }
            sort(a,a+m);
            Out(m);
            for(j=0;j<m;j++)
            {
                putchar(' ');
                Out(a[j]);
            }
            printf("\n");
        }
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值