当前位置: 代码迷 >> 综合 >> hdoj 3729 I'm Telling the Truth (二分图匹配)
  详细解决方案

hdoj 3729 I'm Telling the Truth (二分图匹配)

热度:32   发布时间:2024-01-15 05:05:21.0

http://acm.hdu.edu.cn/showproblem.php?pid=3729
题意:n个人,每个人说自己排名在x~y名,问最多几个人说的是真话,输出最多的人数,和字典序最大的这几个人的编号。
数据范围:n <= 60,1 <= Xi <= Yi <= 100000

当时看到x,y的数据范围是有点被吓住了,但n只有60,而且我也不会什么其他方法,所以就对每个人对从Xi到Yi的每一个数都连一条边,然后暴力跑匈牙利算法,竟然卡过了,先T了几回,突然967ms卡过了,再后来再交又是T了,结果发现是因为我把vis数组开得太大了,每次匹配都要memset结果就疯狂T,真是太菜了。。。
这里写图片描述
而且上网查题解发现,发我的思路没错,就是要暴力,只是建图不需要每条边都存,记录一个x,y就行,每次遍历这个人的每条边就从x到y循环就行,这样空间也能省下很多。
这里还有一个点就是输出字典序最大的答案序列,其实很简单匹配的时候倒着循环,每次尽量先找大的,就能得到字典序最大的了。
还有个会PE的点就是每行末尾不能有空格,每组数据最后都有回车。
我的渣渣版本:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
using namespace std;
int ans[65];
int n,m,T,k;
bool vis[100005];//就是这个数组我之前多打了一个0就导致疯狂T
map<int,int> pr;
struct Edge{int w,v,next;
}e[1000010];
int head[1000010];
void addedge(int u,int v,int w)
{e[k].v=v;e[k].w=w;e[k].next=head[u];head[u]=k++;
}
bool find(int x)
{for(int i=head[x];i;i=e[i].next){if(!vis[e[i].v]){vis[e[i].v]=1;if(pr[e[i].v]==0||find(pr[e[i].v])){pr[e[i].v]=x;return 1;}}}return 0;
}
int main()
{scanf("%d",&T);while(T--){k=1;scanf("%d",&n);int sum=0,num=0;pr=map<int,int>();memset(e,0,sizeof(e));memset(head,0,sizeof(head));for(int i=1;i<=n;i++){int x,y;scanf("%d%d",&x,&y);for(int j=x;j<=y;j++)addedge(i,j,1);}for(int i=n;i>=1;i--)//倒序循环{memset(vis,0,sizeof(vis));if(find(i)) sum++;}printf("%d\n",sum);map<int,int>::iterator it;for(it=pr.begin();it!=pr.end();it++){num++;ans[num]=it->second;}sort(ans+1,ans+1+num);for(int i=1;i<num;i++)printf("%d ",ans[i]);printf("%d",ans[num]);printf("\n");}return 0;
}

借鉴题解后的改良版本

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
using namespace std;
int ans[65];
int n,m,T,k;
bool vis[100005];
map<int,int> pr;
struct Edge{int x,y;
}e[100];//空间一下次省了好多
bool find(int p)
{for(int i=e[p].x;i<=e[p].y;i++){if(!vis[i]){vis[i]=1;if(pr[i]==0||find(pr[i])){pr[i]=p;return 1;}}}return 0;
}
int main()
{scanf("%d",&T);while(T--){k=1;scanf("%d",&n);int sum=0,num=0;pr=map<int,int>();memset(e,0,sizeof(e));for(int i=1;i<=n;i++)scanf("%d%d",&e[i].x,&e[i].y);for(int i=n;i>=1;i--){memset(vis,0,sizeof(vis));if(find(i)) sum++;}printf("%d\n",sum);map<int,int>::iterator it;for(it=pr.begin();it!=pr.end();it++){num++;ans[num]=it->second;}sort(ans+1,ans+1+num);for(int i=1;i<num;i++)printf("%d ",ans[i]);printf("%d",ans[num]);printf("\n");}return 0;
}