T79167 新田忌赛马
Posted -hhs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了T79167 新田忌赛马相关的知识,希望对你有一定的参考价值。
题目背景
田忌又要和齐王赛马了,这一次赛的不止三匹马,田忌请学OI的你帮忙
题目描述
田忌和齐王各有n匹马(1<=n<=1000),他们的编号分别是1-n,给出田忌每条马能胜过齐王的哪些马(非赢则输,不存在平局的情况),每匹马最多出战一次,可以自由安排交战顺序,问田忌最多可以赢多少局。
输入输出格式
输入格式:
一行一个数n, 表示齐王和田忌各自马的数量 下面n行 第i行第一个数c,表示田忌的第i匹马能赢得马的数量,这一行后面有c个数,表示第i匹马能赢得对方的马的编号
输出格式:
一个数ans,表示田忌的最大胜场数
输入样例1:
4 3 2 1 3 1 2 2 2 1 1 3
输出样例1:
3
输入样例2:
8 1 6 4 5 1 4 2 4 3 1 6 5 1 5 1 2 2 4 5 6 3 1 4 2 7 6 4 3 7 6 2
输出样例2:
7
说明
对于20%的数据 n<=20 对于50%的数据 n<=200 对于100%的数据 n<=2000 c<=n
思路:
本题是二分图最大匹配:
1、匈牙利算法(只能拿90分, 被一个无良的出题人卡掉一个点):
核心思想:寻找增广路径,用增广路径求二分图最大匹配。
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<cstring> using namespace std; int n,a,b; int line[2008][2008],use[2008],horse[10008]; int ans=0; long long read() long long x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘)if(ch==‘-‘)f=-1;ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘;ch=getchar(); return x*f; int find(int x)//寻找增广路径 for(int i=1;i<=n;++i)//扫描右图每一个点 if(line[x][i]&&!use[i])//如果x与i可以匹配,并且i没有被拆开尝试匹配并失败 use[i]=1;//标记i在此轮中被拆开尝试匹配 if(horse[i]==0||find(horse[i]))//如果i没有被匹配过,或者现在i的匹配对象可以匹配到别人 horse[i]=x; return 1; return 0; int main() n=read(); for(int i=1;i<=n;++i) a=read(); for(int j=1;j<=a;++j) b=read(); line[i][b]=1; for(int i=1;i<=n;++i) memset(use,0,sizeof(use)); if(find(i)) ans++;//真就能找到一条增广路径,假则否 printf("%d",ans); return 0;
2、网络流:
其实所有的二分图最大匹配问题都可以用网络流来做,并且比匈牙利算法更优。若对网络流有疑问可以看一下算法篇里的网络流。
如样例1的数据,图应该是这样的。其中,S\\T分别为超级源点\\汇点。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<iostream> const int inf=0x7fffffff; using namespace std; int n,m,S,T; int u,v,w; int head[10008],num_edge=0; int deep[10008]; struct Edge int next,to,dis; edge[100008<<1]; queue <int> q; long long read() long long x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘)if(ch==‘-‘)f=-1;ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘;ch=getchar(); return x*f; void addedge(int from,int to,int dis) edge[++num_edge].next=head[from]; edge[num_edge].to=to; edge[num_edge].dis=dis; head[from]=num_edge; bool bfs() memset(deep,0,sizeof(deep)); while(!q.empty()) q.pop(); deep[S]=1; q.push(S); do int u=q.front(); q.pop(); for(int i=head[u];i;i=edge[i].next) int v=edge[i].to; if(deep[v]==0&&edge[i].dis) deep[v]=deep[u]+1; q.push(v); while(!q.empty()); if(deep[T]!=0) return 1; else return 0; int dfs(int u,int dist) if(u==T) return dist; for(int i=head[u];i;i=edge[i].next) if( deep[edge[i].to]==deep[u]+1 && edge[i].dis!=0 ) int di=dfs(edge[i].to,min(dist,edge[i].dis)); if(di>0) edge[i].dis-=di; edge[i+1].dis+=di; return di; return 0; int xiongyali() int ans=0; while(bfs()) while(int di=dfs(S,inf)) ans+=di; return ans; int main() n=read();m=n;S=10002;T=10003; for(int i=1;i<=n;++i) int a,b; a=read(); for(int j=1;j<=a;++j) b=read(); b+=5000; addedge(i,b,1); addedge(b,i,0); for(int i=1;i<=n;++i) addedge(S,i,1); addedge(i,S,0); for(int i=1;i<=n;++i) int j=i+5000; addedge(j,T,1); addedge(T,j,0); printf("%d",xiongyali()); return 0;
以上是关于T79167 新田忌赛马的主要内容,如果未能解决你的问题,请参考以下文章