zoukankan      html  css  js  c++  java
  • HDU 3121 FreeOpen

    被这题整整搞了两天啊,先是官方题解:

    Freeopen
    标程做法是IDA* H函数为三次二分图匹配. 搜索顺序按度来优化.
    这个题生成数据的时候光在关注怎么卡掉一般的搜索了.写了六七个搜索,分别用十个数据让这几个搜索超时.
    但是数据量太少了,导致有一些莫名其妙的网络流AC了.
    此题是npc问题,可以划归到3-sat.所以应该不存在多项式算法.

      

    话说这题数据确实太烂了,这种题目单靠手造数据很难卡掉所有非标程做法的,不但没卡掉别的方法,按标程方法不加强减枝也很难过掉了

    话说过来用这题来练习IDA*和搜索减枝确实不错,一般的IDA*是从少层向多层去搜,这题求最大值,就要IDA*从多向少去搜了,构造h()函数要满足大于等于实际值,从多到少的IDA*并不是一个很实用的方法,层数越多搜到的状态数越多,就像IDA*用二分更慢一样,不过这也是一种IDA*新的使用方法,偶尔会派上用场吧。

    因为这题看起来就和二分匹配很有关系(我可以保证如果比赛时遇到这题我绝对不会向搜索方向去想,或许是二分匹配变形或是网络流什么的),如果想到A*搜索的话用二分图匹配也正常,三次二分图匹配作为A*函数是很大胆的一种做法,这么高复杂度的算法用在频繁调用的h()中就必须要保证他的减枝的有效性。三次二分匹配分别做女生和男生,女生和宠物,男生和宠物,取最小值(多次数据测试证明,第一次二分匹配会使速度变慢),如果这个值加上步数小于上限则跳出。

    至于按度优化没什么可说的,只要不按正序基本都能过了,按度反序都能过的 = =||,我更不会告诉你,按照输入顺序反序15ms哦~~

    然后就是各种减枝了...

      

    写了好久的代码,但由于能力有限,效率很低,500+ms,由于数据问题,可能改一个很小的,甚至无关的地方都可能使时间突变...

      1 #include<cstdio>
    2 #include<cstring>
    3 #include<algorithm>
    4 using namespace std;
    5 #define MIN(x,y) (x<y?x:y)
    6
    7 int g,b,p;
    8 int G,B,P;
    9 int gdeg[22];
    10 int grank[22];
    11 int gb[22],gp[22],bp[22];
    12 bool in(){
    13 char c=getchar();
    14 while(c<=32) c=getchar();
    15 return (c=='1');
    16 }
    17
    18 int vis;
    19 int mat[22];
    20 inline bool find0(int u){
    21 for(int i=0;i<b;i++){
    22 if(B&(1<<i)) continue;
    23 if(!(gb[u]&(1<<i))) continue;
    24 if(vis&(1<<i)) continue;
    25 vis|=(1<<i);
    26 if(mat[i]==-1||find0(mat[i])){
    27 mat[i]=u;
    28 return true;
    29 }
    30 }
    31 return false;
    32 }
    33
    34 inline bool find1(int u){
    35 for(int i=0;i<p;i++){
    36 if(P&(1<<i)) continue;
    37 if(!(gp[u]&(1<<i))) continue;
    38 if(vis&(1<<i)) continue;
    39 vis|=(1<<i);
    40 if(mat[i]==-1||find1(mat[i])){
    41 mat[i]=u;
    42 return true;
    43 }
    44 }
    45 return false;
    46 }
    47
    48 inline bool find2(int u){
    49 for(int i=0;i<p;i++){
    50 if(P&(1<<i)) continue;
    51 if(!(bp[u]&(1<<i))) continue;
    52 if(vis&(1<<i)) continue;
    53 vis|=(1<<i);
    54 if(mat[i]==-1||find2(mat[i])){
    55 mat[i]=u;
    56 return true;
    57 }
    58 }
    59 return false;
    60 }
    61
    62 int dep;
    63 inline bool h(int d,int tg){
    64 int cnt=0;
    65 memset(mat,-1,sizeof(mat));
    66 for(int i=tg;i<g;i++){
    67 vis=0;
    68 if(find0(grank[i])) cnt++;
    69 if(cnt>dep-d) break;
    70 }
    71 if(cnt+d<dep) return false;
    72
    73 cnt=0;
    74 memset(mat,-1,sizeof(mat));
    75 for(int i=tg;i<g;i++){
    76 vis=0;
    77 if(find1(grank[i])) cnt++;
    78 if(cnt>dep-d) break;
    79 }
    80 if(cnt+d<dep) return false;
    81
    82 cnt=0;
    83 memset(mat,-1,sizeof(mat));
    84 for(int i=0;i<b;i++){
    85 if(B&(1<<i)) continue;
    86 vis=0;
    87 if(find2(i)) cnt++;
    88 if(cnt>dep-d) break;
    89 }
    90 if(cnt+d<dep) return false;
    91
    92 return true;
    93 }
    94
    95 bool dfs(int d,int tg){
    96 if(d==dep) return true;
    97 if(!h(d,tg)) return false;
    98
    99 for(int ii=tg;ii<g;ii++){
    100 int i=grank[ii];
    101 G|=(1<<i);
    102 for(int j=0;j<b;j++){
    103 if(B&(1<<j)) continue;
    104 if(!(gb[i]&(1<<j))) continue;
    105 B|=(1<<j);
    106 for(int k=0;k<p;k++){
    107 if(P&(1<<k)) continue;
    108 if(gp[i]&bp[j]&(1<<k)){
    109 P|=(1<<k);
    110 if(dfs(d+1,ii+1)) return true;
    111 P^=(1<<k);
    112 }
    113 }
    114 B^=(1<<j);
    115 }
    116 G^=(1<<i);
    117 }
    118 return false;
    119 }
    120
    121 bool gcmp(const int& a,const int& b){
    122 return gdeg[a]<gdeg[b];
    123 }
    124
    125 int main(){
    126 int t;
    127 scanf("%d",&t);
    128 while(t--){
    129 scanf("%d%d%d",&g,&b,&p);
    130 memset(gb,0,sizeof(gb));
    131 memset(gp,0,sizeof(gp));
    132 memset(bp,0,sizeof(bp));
    133 memset(gdeg,0,sizeof(gdeg));
    134 for(int i=0;i<g;i++){
    135 for(int j=0;j<b;j++){
    136 gb[i]|=(in()<<j);
    137 }
    138 }
    139 for(int i=0;i<g;i++){
    140 for(int j=0;j<p;j++){
    141 gp[i]|=(in()<<j);
    142 }
    143 }
    144 for(int i=0;i<b;i++){
    145 for(int j=0;j<p;j++){
    146 bp[i]|=(in()<<j);
    147 }
    148 }
    149
    150 for(int i=0;i<g;i++){
    151 grank[i]=i;
    152 for(int j=0;j<b;j++){
    153 if(!(gp[i]&bp[j])) gb[i]&=~(1<<j);
    154 if(gb[i]&(1<<j)) gdeg[i]++;
    155 }
    156 }
    157 sort(grank,grank+g,gcmp);
    158 //reverse(grank,grank+g);
    159
    160 G=B=P=0;
    161 dep=MIN(MIN(g,b),p);
    162 while(true){
    163 if(dfs(0,0)) break;
    164 dep--;
    165 }
    166
    167 printf("%d\n",dep);
    168 }
    169 }

      


  • 相关阅读:
    Chrome自带恐龙小游戏的源码研究(四)
    Chrome自带恐龙小游戏的源码研究(三)
    Chrome自带恐龙小游戏的源码研究(二)
    Chrome自带恐龙小游戏的源码研究(一)
    使用HTML5制作简单的RPG游戏
    EventListener中的handleEvent
    canvas drawImage方法不显示图片的解决方案
    canvas转盘抽奖的实现(二)
    股市高手的领悟
    《最伟大的投资习惯》读书笔记
  • 原文地址:https://www.cnblogs.com/ambition/p/FreeOpen.html
Copyright © 2011-2022 走看看