King's Quest POJ - 1904 匈牙利算法的思想+tarjan缩点+染色

题目链接:https://cn.vjudge.net/problem/POJ-1904

自己一开始的想法,打算用匈牙利算法实现,找二分图的最大匹配。但是打了打发现,不太好实现。原因如下:匈牙利算法是不停的找增广路。如果这个题用匈牙利算法实现的时候,就是这个地方:

 1 bool Find(int t)
 2 {
 3     for(int i=1; i<=m; i++)
 4     {
 5         if(line[t][i]&&Exit[i]==0)
 6         {
 7             Exit[i]=1;
 8             if(net[i]==0||Find(net[i]))
 9             {
10                 net[i]=t;
11                 return true;
12             }
13         }
14     }
15 }

 

,这个是找到合法的就返回,无法把所有的情况都找到,所以这个方法不行。

然后再去想tarjan算法,找缩点,也就是图上的两点都能都到达,如果是王子向喜欢的公主连线的话,连一条单向边,如果是公主喜欢的王子的话,然后再从公主连向王子一条单向边,这样,就能够在最大匹配的图上实现一个连通图的建立.

但是注意这个题有个坑点,在构成连通图的时候,有的王子不喜欢某个公主,但是在图上也有可能通过别的点联通起来,这个时候就需要特判一下了。

AC代码:

  1 #include<iostream>
  2 #include<stack>
  3 #include<iomanip>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<string>
  7 #include<cstring>
  8 #include<queue>
  9 #include<vector>
 10 #include<stdio.h>
 11 #include<map>
 12 using namespace std;
 13 # define inf 0x3f3f3f3f
 14 # define ll long long
 15 const int N = 4000+100 ;
 16 const int M = 250000+100 ;
 17 struct node
 18 {
 19     int to;
 20     int nex;
 21 } edge[M];
 22 int head[M],low[N],dfn[N],istack[N];
 23 int num,ind,col,n,m;
 24 stack<int>q;
 25 vector<int>wakaka[N];
 26 vector<int>w1;
 27 vector<int>ans[N];
 28 int Map[2010][2010];
 29 void init()
 30 {
 31     while(!q.empty())q.pop();
 32     memset(head,-1,sizeof(head));
 33     num=0,ind=0,col=0;
 34     memset(low,0,sizeof(low));
 35     memset(dfn,0,sizeof(dfn));
 36     memset(istack,0,sizeof(istack));
 37 }
 38 void addedge(int fr,int to)
 39 {
 40     edge[num].to=to;
 41     edge[num].nex=head[fr];
 42     head[fr]=num++;
 43 }
 44 void tarjan(int u,int root)
 45 {
 46     q.push(u);
 47     low[u]=dfn[u]=++ind;
 48     for(int i=head[u]; i!=-1; i=edge[i].nex)
 49     {
 50         int v=edge[i].to;
 51         if(dfn[v]==0)
 52         {
 53             tarjan(v,u);
 54             low[u]=min(low[u],low[v]);
 55         }
 56         else if(istack[v]==0)
 57         {
 58             low[u]=min(low[u],dfn[v]);
 59         }
 60     }
 61     if(low[u]==dfn[u])
 62     {
 63         int t;
 64         col++;
 65         do
 66         {
 67             t=q.top();
 68             q.pop();
 69             istack[t]=col;
 70             wakaka[col].push_back(t);
 71         }
 72         while(t!=u);
 73     }
 74 }
 75 int main()
 76 {
 77     init();
 78     scanf("%d",&n);
 79     int t;
 80     for(int i=1; i<=n; i++)
 81     {
 82         scanf("%d",&m);
 83         for(int j=1; j<=m; j++)
 84         {
 85             scanf("%d",&t);
 86             addedge(i,t+n);
 87             Map[i][t]=1;
 88         }
 89     }
 90     for(int i=1; i<=n; i++)
 91     {
 92         scanf("%d",&t);
 93         addedge(t+n,i);
 94        // Map[t][i]=1;
 95     }
 96     for(int i=1; i<=n; i++)
 97     {
 98         if(dfn[i]==0)
 99         {
100             tarjan(i,1);
101         }
102     }
103     for(int i=1; i<=col; i++)
104     {
105         sort(wakaka[i].begin(),wakaka[i].end());
106         int len=wakaka[i].size();
107         for(int j=0; j<len; j++)
108         {
109             int u=wakaka[i][j];
110             if(u<=n)w1.push_back(u);
111             else 
112             {
113                 int len2=w1.size();
114                 for(int k=0; k<len2; k++)
115                 {
116                 if(Map[w1[k]][u-n])//判断是不是有相互喜欢的关系
117                     ans[w1[k]].push_back(u-n);
118                 }
119             }
120         }
121         w1.clear();
122     }
123     for(int i=1; i<=n; i++)
124     {
125     sort(ans[i].begin(),ans[i].end());
126         int len=ans[i].size();
127         printf("%d",len);
128         for(int j=0; j<len; j++)
129         {
130             printf(" %d",ans[i][j]);
131         }
132         printf("\n");
133     }
134     return 0;
135 }

 

转载于:https://www.cnblogs.com/letlifestop/p/10262802.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值