HDU 4979: 更好的DLX模板 + 打表
来源:互联网 发布:剑网三盾太捏脸数据 编辑:程序博客网 时间:2024/06/05 23:03
本题构造矩阵并不难,用所有可能出现的组合当列,用所有可能买到的组合当行,然后跑一个可重复匹配即可……
恶心的事情在于这题数据量有点大,C84 = 70行,可重复覆盖有点吃不消。
所以应该打表……但是有几组数据真是需要跑好长时间才能跑出来,感觉是需要手算的,一组是8 3 2, 一组是8 5 4.
判断是否为1的话,我们可以用二进制判断,12345能够覆盖1234 => 11111 & 1111 == 1111这样就可以了。
嗯其实最主要的目的是修一下自己的DLX模板,之前模板为什么写得跟shi一样……
#include<iostream>#include<stdio.h>#include<string.h>#include<math.h>using namespace std; const int INF=1<<30;const int MAXNUM=5000; int u[MAXNUM], d[MAXNUM], l[MAXNUM], r[MAXNUM];//上下左右int s[MAXNUM], col[MAXNUM], row[MAXNUM];//s[i]:第i列有几个节点,即有几个1,col[i]能告诉你i这个节点在第几列,row同样struct Info // 如有需要,用这个结构体记录行列表头的附加信息{int bit_hash;};Info column_info[MAXNUM], row_info[MAXNUM];int row_selected[MAXNUM]; // 是否删过行 int head;//总表头,其实就是0号节点int p_nodes;//目前用了多少节点int column_num=0;//主程序中填写列数, 行数,也可以动态填写int row_num=0;int ans_num=0; ///////////INSERT UNIQUE THINGS HEREint n, m, k;int t;int bit_hash_idx=1;int two[10];/////////////////////////////////// void del(int c)//注意和精确模板的差别,不用动{ for(int i=d[c]; i!=c; i=d[i]) { l[ r[i] ] = l[i]; r[ l[i] ] = r[i]; s[ col[i] ] --; } return;} void resume(int c)//恢复上面的操作,不用动{ for(int i=u[c]; i!=c; i=u[i]) { s[ col[i] ] ++; r[ l[i] ] =i; l[ r[i] ] = i; } return;} int Hash() // 固定的Astar用函数,只需要修改hs下标 > 列数{ int ret=0; int hs[100]={0};//给每列用的,所以至少要开到列数那么大 for(int c=r[head]; c!=head;c=r[c]) { if(hs[c]==0) { hs[c]=1; ret++; for(int i=d[c]; i!=c; i=d[i]) { for(int j=r[i]; j!=i; j=r[j]) { hs[ col[j] ] =1; } } } } return ret;} void DFS(int depth, int cost) //基本不用动,看看是否需要记录答案等就可以了{ ////TEST //cout<<depth<<endl; if(depth-1 + Hash() > row_num) return; if(cost >= ans_num) return; if(r[head] == head) { ans_num=min(cost, ans_num); return;//矩阵被删干净了 } int min1=INF, now;//挑一个1数最少列的先删 for(int t=r[head]; t!=head; t=r[t]) { if(s[t]==0) return; if(s[t] <=min1 ) { min1=s[t]; now=t; } } //TEST //cout<<"now: "<<now<<endl; int i, j; for(i=u[now]; i!=now; i=u[i]) { del(i); //↑注意和精确模板的差别 //枚举这一列每个1由哪行来贡献,这行即为暂时性的答案,//如果需记录都删了哪些行,此时记录ans[depth]=row[i]就可以了int now_ans = row[i];row_selected[now_ans]++;if(row_selected[now_ans]==1)cost++; ///TEST //cout<<"ans[depth]: "<<ans[depth]<<endl; for(j=r[i]; j!=i; j=r[j]) { del(j); } DFS(depth+1, cost); for(j=l[i]; j!=i; j=l[j]) { resume(j); }row_selected[now_ans]--; if(row_selected[now_ans]==0) cost--; resume(i); } return;} void init(){ memset(u,0,sizeof(u)); memset(d,0,sizeof(d)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(s,0,sizeof(s)); memset(col,0,sizeof(col));memset(row,0, sizeof(row));memset(column_info, 0, sizeof(column_info));memset(row_info, 0, sizeof(row_info)); head=0; p_nodes=0; //INSERT UNIQUE THINGS HEREbit_hash_idx = 1;ans_num = INF;return;} int insert_node(int row_first1, int j, int now_row)//知道我当前的行第一个是谁,我在第j列, 第now_row行,基本不用动{ p_nodes++; s[j] ++; u[p_nodes] = u[j]; d[ u[j] ] = p_nodes; u[j] = p_nodes; d[p_nodes] = j; col[p_nodes] = j;//和列的关系处理完毕 if(row_first1==-1) { l[p_nodes] = r[p_nodes] = p_nodes; row_first1=p_nodes; } else { l[p_nodes] = l[row_first1]; r[ l[row_first1] ] = p_nodes; r[p_nodes] = row_first1; l[ row_first1 ]=p_nodes;//和行的关系处理完毕 } row[p_nodes]=now_row; return row_first1; } void insert_row(int idx)//新建一行,一行里会插入若干结点,idx = 这是第几行{ int row_first1=-1;//看看这一行是不是已经有第一个1了 int i; for(i=1; i<=column_num; i++) {if( (row_info[idx].bit_hash & column_info[i].bit_hash ) == column_info[i].bit_hash) //是1的条件row_first1=insert_node(row_first1, i, idx); } return;} void InitLinks()//注意:该链表两个方向都是循环的,最上面的上面指最下面{ int i; r[head]=1; l[head]=column_num; for(i=1;i<=column_num;i++)//制作列的表头,使用结点1~column_num { l[i]=i-1; r[i]=i+1; if(i==column_num) r[i]=head; u[i]=i; d[i]=i; s[i]=0; col[i]=i;//如有需要,在这里填写列表头的Info,由于已经填写完了就不填写了 } p_nodes=column_num; for(i=1; i<=row_num; i++) { insert_row(i);//可以在这里填写行表头info }}void GenerateBit(int now, int now_value, int max_length, Info target[], int pre, int max_idx)//本题特有的填写行列表头函数{if(now == max_length+1){target[bit_hash_idx].bit_hash = now_value;bit_hash_idx++;return;}int i;for(i=pre+1;i<=n;i++){now_value += two[i-1];GenerateBit(now+1, now_value, max_length, target, i, max_idx);now_value -= two[i-1];if(bit_hash_idx > max_idx)return;}return;}int C(int x, int y){int i;int up=1, down = 1;for(i=1; i<=y; i++)up*=x+1-i;for(i=y; i>=1; i--)down *= i;return up/down;} int main(){//freopen("1.txt", "w", stdout);ofstream fout("1.txt");two[0]=1;for(int tmp=1;tmp<=9;tmp++)two[tmp] = 2*two[tmp-1]; scanf("%d", &t); for(int files=1; files<=t; files++) {scanf("%d %d %d", &n, &m, &k); column_num=C(n, k);row_num = C(n, m);GenerateBit(1, 0, k, column_info, 0, column_num);bit_hash_idx = 1;GenerateBit(1, 0, m, row_info, 0, row_num); InitLinks(); DFS(1,0); printf("Case #%d: ", files);cout<<ans_num<<", "; } system("pause"); return 0;}
0 0
- HDU 4979: 更好的DLX模板 + 打表
- hdu 4979 A simple math problem. DLX(多重覆盖)+打表
- hdu - 4979 - A simple math problem.(可重复覆盖DLX + 打表)
- [DLX精确覆盖+打表] hdu 2518 Dominoes
- hdu 5046 二分+DLX模板
- SGU224 K皇后 DLX+打表
- DLX 模板
- DLX模板
- DLX模板
- 模板--DLX
- DLX模板
- dlx模板
- HDU 5046 ( Airport ) DLX模板题,手残again
- [DLX 数独 模板题] HDU 1426 Sudoku Killer
- [HDU 4069]刷的水DLX
- hdu 1250 (大整数模板+打表)
- hdu 1041 打表:递推+大数 模板
- DLX模板+小栗子
- 测试用例设计白皮书--错误推测方法
- 分享一个链接
- 寻找最大的k个数
- Golang_tag
- 测试用例设计白皮书--因果图方法
- HDU 4979: 更好的DLX模板 + 打表
- 二维数组的行地址与列地址应用举例
- Linux 开发板网络设置
- OK6410(s3c6410)时钟系统
- Android SQLite数据库使用 学习与代码实践
- 测试用例设计白皮书--判定表驱动分析方法
- 多线程编程
- 图片3d轮放查看效果(V2.0):使用鼠标拖动实现图片的轮放
- IOS之NSArray 中调用的方法详解