9.22考试 crf的军训 题解

  做这道题时由于第一道题太水了,第一反应是NOIP T2级别的题,需要拿上70~100的分,然后就开始分析,当然最后事实证明我错了……

  这道题当时首先联想到了 NOIP2016愤怒的小鸟 当然,数据范围不允许,但是我当时只是为了先拿到小数据的分数,所以先没考虑数据范围,在这里简单提一下:首先我先枚举了每一个状态,然后判断这个状态中的书是否能连在一起,然后就是一个2^(2*n)的转移,好吧,我承认,不是正宗的愤怒的小鸟打法,是当时集中生智编出来的,但是对于n<=10的复杂度还是够用的。

  然后对于小于80(我自己假定的一个数据范围)打了一个小爆搜,挂了。

  对于大于80的,也就是对应的正解部分,我首先想到的是贪心,然而被我自己rand出来的数据和状压一对比卡掉了,然后以为是动归,想了半天也没写出转移方程,于是也跪了,然后就开始往图论那里想,却一无所获。但是由于前一天刚刚看完《骗分导论》,想着万一有一些点仁义的不去卡我贪心呢?于是就把贪心交了上去,结果全WA了,拿到数据后输出了贪心答案-2得了60分,事后想一想也是,贪心一定比正确答案只多不少,减去一些数可能就是正解。但当时谁能想到呢?


                   蒟蒻与正解的分割线                      


  现在我来说正解,二分图最小路径(链)覆盖,由于造数据的标程有误,我就只说最正确的了(在此鸣谢撸串神的发现)。

  我们在二分图上跑最小链覆盖有一个巨大的前提:这个图一定是DAG,然而此题由于是要求“不超过”,所以会有两个规格一模一样的书之间有环,不过由于两本相同的书一定可以放在一起,所以我们只要把他们缩一下就行。

  然后由于最小链覆盖=n-最大匹配,所以我们只要向能放在他之后的点建边即可,然后就是最大匹配了。

 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-ans);
89     return 0;
90 }
View Code
原文地址:https://www.cnblogs.com/liutianrui/p/7581857.html