现在的位置: 首页 > 综合 > 正文

poj 3074/poj 3076(精确覆盖)

2017年12月13日 ⁄ 综合 ⁄ 共 3109字 ⁄ 字号 评论关闭

两个题都是数独,题意很明确。

建图的思路大神写的很好:

:一共9 * 9 * 9 == 729行。一共9 * 9小格,每一格有9种可能性(1 - 9), 每一种可能都对应着一行。

:一共(9 + 9 + 9) * 9 + 81 == 324 种前面三个9分别代表着9行9列和9小 块。乘以9的意思是9种可能,因为每种可能只可以选择一个。81代表着81个 小格,限制着每一个小格只可以放一个地方。

我个人的理解是行就是所有的可能,列就是限制条件,这里就是列

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <string>
using namespace std;
#define For(i,a) for(i=0;i<a;i++)
#define Foru(i,a,b) for(i=a;i<=b;i++)
#define Ford(i,a,b) for(i=a;i>=b;i--)
#define clr(ar,vel) memset(ar,vel,sizeof(ar))
#define PB push_back
#define maxint 0x7fffffff

int ans[300];
string s;
const int maxn = 502011;
const int head = 0;
int size;
int col[maxn];
int row[maxn];
int cell[maxn];

int R[maxn], L[maxn], U[maxn], D[maxn];
int S[maxn], C[maxn], O[maxn], H[maxn], X[maxn];

void remove(const int &c) { 
	//cout << "remove   " << c << endl;
	//remove column c and all row i that A[i][c] == 1 
	L[R[c]] = L[c]; R[L[c]] = R[c]; 
	//remove column c; 
	for (int i = D[c]; i != c; i = D[i]) { 
	//remove i that A[i][c] == 1 
		for (int j = R[i]; j != i; j = R[j]) { 
			//cout << "remove" << endl;
			U[D[j]] = U[j]; D[U[j]] = D[j]; --S[C[j]]; //decrease the count of column C[j];
		}
	}
}
void resume(const int &c) { 
	for (int i = U[c]; i != c; i = U[i]) { 
		for (int j = L[i]; j != i; j = L[j]) { 
			++S[C[j]]; 
			U[D[j]] = j; 
			D[U[j]] = j; 
		} 
	} 
	L[R[c]] = c; 
	R[L[c]] = c; 
}
bool dfs(const int &k) { 
	
	if (R[head] == head) { 
	//One of the answers has been found. 
		//cout << "answer  " << k << endl;
		for(int i = 0; i < k; i ++){
			int num, pos;
			num = X[O[i]]/256;
			pos = X[O[i]]%256;
			s[pos] = num+'A'-1;
			//cout << num << ' ' << pos << endl;
		}
		for(int i = 0; i < 16; i ++) {
			for(int j = 0; j < 16; j ++){
				cout << s[i*16+j];
			}
			cout << endl;
		}
		return true; 
	} 
	
	int s(maxint), c; 
	for (int t = R[head]; t != head; t = R[t]) { 
	//select the column c which has the fewest number of element. 
		if (S[t] < s) { 
			s = S[t]; 
			c = t; 
		} 
	} 
	//cout << k << endl;
	remove(c); 
	for (int i = D[c]; i != c; i = D[i]) { 
		O[k] = i;
		//record the answer. 
		for (int j = R[i]; j != i; j = R[j]) { 
			remove(C[j]); 
		} 
		if (dfs(k + 1)) {return true;} 
		for (int j = L[i]; j != i; j = L[j]) { 
			resume(C[j]); 
		}
	} 
	resume(c); 
	return false;
}

void link(int r,int c)  
{  
    ++S[C[size]=c];  
    D[size]=D[c];  
    U[D[c]]=size;  
    U[size]=c;  
    D[c]=size;  
    if(H[r]<0)H[r]=L[size]=R[size]=size;  
    else  
    {  
        R[size]=R[H[r]];  
        L[R[H[r]]]=size;  
        L[size]=H[r];  
        R[H[r]]=size;  
    }  
    X[size++]=r;  
}

void init(int m){
	clr(col,0);
	clr(row,0);
	clr(cell,0);
	clr(ans, -1);
	clr(H, -1);
	for(int i = 0; i <= m; i ++){
		S[i] = 0;
		R[i] = i+1;
		L[i+1] = i;
		U[i] = D[i] = i;
	}
	R[m] = 0;
	L[0] = m;
	size = m+1;
}

int main(){
	int rownum;
	int c1, c2, c3, c4;
	char str[20];
	int flag = 0;
	while(~scanf("%s",str)){
		if(flag) cout << endl;
		flag = 1;
		s = str;
		for(int i = 1; i < 16; i ++) {
			scanf("%s",str);
			s+= str;
		}
		//cout << s << endl;
		init(1024);
		rownum = 1;
	
		int cnt = 0;
		//for(int i = 0; i < 10; i ++) cout << ans[i] << ' ';cout << endl;
		for(int i = 1; i <= 16; i ++){
			for(int j = 1; j <= 16; j ++){
				if(s[cnt] != '-'){
					int w = s[cnt] - 'A'+1;
					ans[cnt] = w;	
//					cout << w << endl;
					chance(i, j, w, rownum, c1, c2, c3, c4);
					link(rownum,c1);
					link(rownum,c2);
					link(rownum,c3);
					link(rownum,c4); 
					

//					cout <<  c1 << ' ' << c2 << ' ' << c3 << ' ' << c4 << endl;
					//system("pause");
					row[c1] = 1;
					col[c2] = 1;
					cell[c3] = 1;
				}
				cnt++;
			}
		}
		//for(int i = 0; i < 10; i ++) cout << ans[i] << ' ';cout << endl;
		//for(int i = 0; i < 324; i ++) cout << S[i] << ' ' ;cout << endl;
		
		for(int i = 1; i <= 16; i ++){
			for(int j = 1; j <= 16; j ++){
				if( ans[i*16-16+j-1] == -1){
					for(int w = 1; w <= 16; w ++){
						chance(i, j, w, rownum, c1, c2, c3, c4);
						if( row[c1] || col[c2] || cell[c3] ) continue;
						
						link(rownum,c1);
						link(rownum,c2);
						link(rownum,c3);
						link(rownum,c4); 
//						cout << c4 << endl;

					}
					//rownum++;
				}
			}
		}
		dfs(0);
		//cout << "answer" <<  endl;
			
	}
	return 0;
}
【上篇】
【下篇】

抱歉!评论已关闭.