【日记】6.15
今天上午的状态不是很好,就做了2道题,一个炮兵阵地,另一个是英文名字、具体忘了。
下午的考试难度应该介于NOIp和NOI之间吧,感觉发挥的还行,已经做到我能做的极限了。
①导弹拦截,变成三维空间的了,而且要求的是最长上升序列的长,第一问很简单,和原来的一样,1D1D动态规划,需要注意的是导弹被拦截的顺序是可以改变的,例如拦截完第3个后可以再去拦第一个,所以要先对数据排序。
不过第二问就有点儿不一样了,因为要求的是最长上升序列,所以这个序列就不满足偏序关系了,也就是所谓的dilworth定理(最小链划分 = 最长反链),这个的证明可以找一本组合数学或离散数学去看看,或者去网上搜索下,其实我也只是知道了而已……没有打算会证明。那么第二问,我们来分析下,一个导弹被拦截了,如果不是这个上升序列的第一个,那么肯定有个前趋,最后的结果就是每个点都有覆盖,我们很容易就能想到的是二分图结构的最小路径覆盖,利用(最小路径覆盖=|P|-其中最大匹配数)就可以做出第二问了。
至于超了一组的原因,应该是求最大匹配的时候用的是最简单的算法,时间复杂度较高的原因。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 *Prob : bomba 3 *Data : 2012-6-15 4 *Sol : ①动归 ②二分图 5 *Author : ZhouHang 6 */ 7 8 #include <cstdio> 9 #include <algorithm> 10 #include <cstring> 11 12 #define MaxN 1100 13 14 using namespace std; 15 16 struct node 17 { 18 int x,y,z; 19 } a[MaxN]; 20 int n,ans; 21 int f[MaxN]; 22 //二分图 23 int maxnum; 24 int link[MaxN]; 25 bool v[MaxN]; 26 bool map[MaxN][MaxN]; 27 28 bool cmp(int i,int j) 29 { 30 if (a[i].x>a[j].x&&a[i].y>a[j].y&&a[i].z>a[j].z) return true; 31 return false; 32 } 33 34 void Make_Graph() 35 { 36 memset(map,false,sizeof(map)); 37 for (int i=1; i<=n; i++) 38 for (int j=1; j<=n; j++) 39 { 40 if (i==j) continue; 41 if (cmp(i,j)) map[i][j]=true; 42 } 43 } 44 45 bool find(int i) 46 { 47 for (int k=1; k<=n; k++) 48 if ( (!v[k])&&map[i][k] ) 49 { 50 v[k]=true; 51 if ( link[k]==0||find(link[k]) ) 52 { 53 link[k]=i; 54 return true; 55 } 56 } 57 return false; 58 } 59 60 void work() 61 { 62 maxnum=0; 63 for (int i=1; i<=n; i++) 64 { 65 memset(v,false,sizeof(v)); 66 if ( find(i) ) maxnum++; 67 } 68 } 69 70 void Swap(node &i,node &j) 71 { 72 node c=i; 73 i=j; j=c; 74 } 75 76 bool check(int i,int j) 77 { 78 if (a[i].x>a[j].x) return true; 79 if (a[i].x<a[j].x) return false; 80 if (a[i].y>a[j].y) return true; 81 if (a[i].y<a[j].y) return false; 82 if (a[i].z>a[j].z) return true; 83 return false; 84 } 85 86 int main() 87 { 88 freopen("bomba.in","r",stdin); 89 freopen("bomba.out","w",stdout); 90 91 scanf("%d",&n); 92 for (int i=1; i<=n; i++) 93 scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); 94 95 for (int i=1; i<=n; i++) 96 for (int j=i+1; j<=n; j++) 97 { 98 if (check(i,j)) Swap(a[i],a[j]); 99 } 100 101 //first question 102 for (int i=1; i<=n; i++) f[i]=1; 103 ans=1; 104 for (int x=2; x<=n; x++) 105 for (int y=1; y<x; y++) 106 if (cmp(x,y)) 107 { 108 f[x]=max(f[x],f[y]+1); 109 if (f[x]>ans) ans=f[x]; 110 } 111 112 printf("%d\n",ans); 113 114 //sencond question 115 Make_Graph(); 116 memset(link,0,sizeof(link)); 117 work(); 118 printf("%d\n",n-maxnum); 119 120 fclose(stdin); fclose(stdout); 121 return 0; 122 }
③新打鼹鼠
这道题我果断写了个最简单的动态规划,也就是最好想的一维动归f[i]=max(f[j])+w[i]时间复杂度是O(M2)的
这道题的dp是不满足决策单调性的,所以没有方法从动归的角度优化,就要去从别的方面考虑,或许把状态离散化成坐标的点会更好点,但是后面的我就想不到了,等待老师的集体报告。