题目大概说n个学生,都各自有一个互不相同的成绩排名,他们各自说了他们成绩排名所在区间,问最多有几个学生没说谎以及字典序最大的没说谎的学生序列。
学生作为一个X部的点,排名作为Y部的点,学生与其成绩排名的区间的各个点之间连边,这其实就是求这个二分图的最大匹配。
排名最多10W,边容量为1,不离散化跑网络流(Dinic?!)好像应该也是没问题的。。不过还是学习了别人的离散化,自己写的错了。。
这题关键是要字典序最大,不会。。又学习了别人的写法——按字典序枚举学生,加相关边,依次跑最大流。好有道理!
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 444 8 #define MAXM 444*444*2 9 struct Edge{ 10 int flag,v,cap,flow,next; 11 }edge[MAXM]; 12 int vs,vt,NV,NE,head[MAXN]; 13 void addEdge(int u,int v,int cap,int flag){ 14 edge[NE].flag=flag; 15 edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0; 16 edge[NE].next=head[u]; head[u]=NE++; 17 edge[NE].flag=flag; 18 edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0; 19 edge[NE].next=head[v]; head[v]=NE++; 20 } 21 int level[MAXN]; 22 int gap[MAXN]; 23 void bfs(){ 24 memset(level,-1,sizeof(level)); 25 memset(gap,0,sizeof(gap)); 26 level[vt]=0; 27 gap[level[vt]]++; 28 queue<int> que; 29 que.push(vt); 30 while(!que.empty()){ 31 int u=que.front(); que.pop(); 32 for(int i=head[u]; i!=-1; i=edge[i].next){ 33 int v=edge[i].v; 34 if(level[v]!=-1) continue; 35 level[v]=level[u]+1; 36 gap[level[v]]++; 37 que.push(v); 38 } 39 } 40 } 41 int pre[MAXN]; 42 int cur[MAXN]; 43 int ISAP(){ 44 bfs(); 45 memset(pre,-1,sizeof(pre)); 46 memcpy(cur,head,sizeof(head)); 47 int u=pre[vs]=vs,flow=0,aug=INF; 48 gap[0]=NV; 49 while(level[vs]<NV){ 50 bool flag=false; 51 for(int &i=cur[u]; i!=-1; i=edge[i].next){ 52 int v=edge[i].v; 53 if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){ 54 flag=true; 55 pre[v]=u; 56 u=v; 57 aug=min(aug,edge[i].cap-edge[i].flow); 58 if(v==vt){ 59 flow+=aug; 60 for(u=pre[v]; v!=vs; v=u,u=pre[u]){ 61 edge[cur[u]].flow+=aug; 62 edge[cur[u]^1].flow-=aug; 63 } 64 aug=INF; 65 } 66 break; 67 } 68 } 69 if(flag) continue; 70 int minlevel=NV; 71 for(int i=head[u]; i!=-1; i=edge[i].next){ 72 int v=edge[i].v; 73 if(edge[i].cap!=edge[i].flow && level[v]<minlevel){ 74 minlevel=level[v]; 75 cur[u]=i; 76 } 77 } 78 if(--gap[level[u]]==0) break; 79 level[u]=minlevel+1; 80 gap[level[u]]++; 81 u=pre[u]; 82 } 83 return flow; 84 } 85 int x[66],y[66],point[333],pn; 86 int idx[110000]; 87 int main(){ 88 int t,n; 89 scanf("%d",&t); 90 while(t--){ 91 scanf("%d",&n); 92 pn=0; 93 int mx=0; 94 for(int i=1; i<=n; ++i){ 95 scanf("%d%d",x+i,y+i); 96 point[pn++]=x[i]; 97 point[pn++]=++y[i]; 98 } 99 sort(point,point+pn); 100 pn=unique(point,point+pn)-point; 101 vs=0; vt=pn+n; NV=vt+1; NE=0; 102 memset(head,-1,sizeof(head)); 103 for(int i=1; i<pn; ++i){ 104 addEdge(i,vt,point[i]-point[i-1],0); 105 for(int j=1; j<=n; ++j){ 106 if(x[j]<=point[i-1] && point[i]<=y[j]) addEdge(j+pn-1,i,1,0); 107 } 108 } 109 int flow=0; 110 for(int i=n; i>=1; --i){ 111 addEdge(vs,i+pn-1,1,i); 112 flow+=ISAP(); 113 } 114 printf("%d ",flow); 115 int ans[66],an=0; 116 for(int i=head[vs]; i!=-1; i=edge[i].next){ 117 if(edge[i].cap==edge[i].flow && edge[i].flag) ans[an++]=edge[i].flag; 118 } 119 sort(ans,ans+an); 120 for(int i=0; i<an; ++i){ 121 if(i) putchar(' '); 122 printf("%d",ans[i]); 123 } 124 putchar(' '); 125 } 126 return 0; 127 }