9.22考试 crf的军训 题解
做这道题时由于第一道题太水了,第一反应是NOIP T2级别的题,需要拿上70~100的分,然后就开始分析,当然最后事实证明我错了……
这道题当时首先联想到了 NOIP2016愤怒的小鸟 当然,数据范围不允许,但是我当时只是为了先拿到小数据的分数,所以先没考虑数据范围,在这里简单提一下:首先我先枚举了每一个状态,然后判断这个状态中的书是否能连在一起,然后就是一个2^(2*n)的转移,好吧,我承认,不是正宗的愤怒的小鸟打法,是当时集中生智编出来的,但是对于n<=10的复杂度还是够用的。
然后对于小于80(我自己假定的一个数据范围)打了一个小爆搜,挂了。
对于大于80的,也就是对应的正解部分,我首先想到的是贪心,然而被我自己rand出来的数据和状压一对比卡掉了,然后以为是动归,想了半天也没写出转移方程,于是也跪了,然后就开始往图论那里想,却一无所获。但是由于前一天刚刚看完《骗分导论》,想着万一有一些点仁义的不去卡我贪心呢?于是就把贪心交了上去,结果全WA了,拿到数据后输出了贪心答案-2得了60分,事后想一想也是,贪心一定比正确答案只多不少,减去一些数可能就是正解。但当时谁能想到呢?
蒟蒻与正解的分割线
现在我来说正解,二分图最小路径(链)覆盖,由于造数据的标程有误,我就只说最正确的了(在此鸣谢撸串神的发现)。
我们在二分图上跑最小链覆盖有一个巨大的前提:这个图一定是DAG,然而此题由于是要求“不超过”,所以会有两个规格一模一样的书之间有环,不过由于两本相同的书一定可以放在一起,所以我们只要把他们缩一下就行。
然后由于最小链覆盖=n-最大匹配,所以我们只要向能放在他之后的点建边即可,然后就是最大匹配了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<vector> 10 #define N 305 11 using namespace std; 12 int n; 13 struct no 14 { 15 int x,y; 16 }node[N],node2[N]; 17 int px(no a,no b) 18 { 19 if(a.x==b.x)return a.y<b.y; 20 return a.x<b.x; 21 } 22 struct ro 23 { 24 int to,next; 25 }road[N*N*10]; 26 int zz,a[N]; 27 void build(int x,int y) 28 { 29 zz++; 30 road[zz].next=a[x]; 31 road[zz].to=y; 32 a[x]=zz; 33 } 34 bool fw[N]; 35 int b[3*N]; 36 bool find(int x) 37 { 38 for(int i=a[x];i>0;i=road[i].next) 39 { 40 int y=road[i].to; 41 if(!fw[y]) 42 { 43 fw[y]=1; 44 if(!b[y]||find(b[y])) 45 { 46 b[y]=x; 47 return 1; 48 } 49 } 50 } 51 return 0; 52 } 53 int main() 54 { 55 scanf("%d",&n); 56 for(int i=1;i<=n;i++) 57 { 58 scanf("%d%d",&node2[i].x,&node2[i].y); 59 } 60 sort(node2+1,node2+n+1,px); 61 int zzh=0; 62 for(int i=1;i<=n;i++) 63 { 64 if(node2[i].x!=node[zzh].y||node2[i].y!=node[zzh].y) 65 { 66 zzh++; 67 node[zzh]=node2[i]; 68 } 69 } 70 n=zzh; 71 for(int i=1;i<=n;i++) 72 { 73 for(int j=1;j<=n;j++) 74 { 75 if(i==j)continue; 76 if(node[i].x<=node[j].x&&node[i].y<=node[j].y) 77 build(i,j); 78 } 79 } 80 int ans=0; 81 for(int i=1;i<=n;i++) 82 { 83 memset(fw,0,sizeof(fw)); 84 if(find(i)) 85 ans++; 86 87 } 88 printf("%d\n",n-ans); 89 return 0; 90 }