社区讨论

70求调,T了6个点

P1074[NOIP 2009 提高组] 靶形数独参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@mhjo60vv
此快照首次捕获于
2025/11/04 05:45
4 个月前
此快照最后确认于
2025/11/04 05:45
4 个月前
查看原帖
CPP
#include<bits/stdc++.h>
using namespace std;
const int g[10][10]={
    {0,0,0,0,0,0,0,0,0,0},
    {0,1,1,1,2,2,2,3,3,3},
    {0,1,1,1,2,2,2,3,3,3},
    {0,1,1,1,2,2,2,3,3,3},
    {0,4,4,4,5,5,5,6,6,6},
    {0,4,4,4,5,5,5,6,6,6},
    {0,4,4,4,5,5,5,6,6,6},
    {0,7,7,7,8,8,8,9,9,9},
    {0,7,7,7,8,8,8,9,9,9},
    {0,7,7,7,8,8,8,9,9,9},
},p[10][2]={{0,0},{1,1},{1,4},{1,7},{4,1},{4,4},{4,7},{7,1},{7,4},{7,7}};
int ans[10][10],score,use[10];//当前填的数独,当前最高分,当前使用了几次数字
vector<int>box[10];//box[i][j]表示第i宫第j个格子填了什么
struct cnt0{
    int ind,total;//原先在第几行,0的数量
}cntzero[10];//统计每一行0的数量
bool cmp(cnt0 a,cnt0 b){return a.total<b.total;}
bool check(){
    int result=0;
    for(int i=1;i<=9;++i){
        for(int j=1;j<=9;++j){
            int d=10-max(abs(i-5),abs(j-5));
            if(ans[i][j])result+=d*ans[i][j];
            else result+=9*d;
        }
    }
    if(result<=score)return 1;//最优性剪枝
    for(int i=1;i<=9;++i)
    	if(use[i]>9)
    		return 1;
    return 0;
}
int calc(){//统计分数
    int result=0;
    for(int i=1;i<=9;++i)
        for(int j=1;j<=9;++j)
            result+=(10-max(abs(i-5),abs(j-5)))*ans[i][j];
    return result;
}
void dfs(int x,int y){
    if(check())return;
    /*
    if((double)clock()/CLOCKS_PER_SEC>=0.997){
        if(score)printf("%d\n",score);
        else printf("-1\n");
        exit(0);
    }
    *///这里是卡时代码,使用后会WA
    if(x>9||y>9){
        score=max(score,calc());
        return;
    }
    int row=cntzero[x].ind;
    if(ans[row][y]){
        if(y==9)dfs(x+1,1);
        else dfs(x,y+1);
        return;
    }
    if(10-max(abs(row-5),abs(y-5))>3)
        //把分值高的点的分数从大到小枚举
        for(int i=1;i<=9;++i){
        	int tmp1=g[row][y],tmp2=(row-1)%3*3+(y-1)%3+1;
            //表示第row行,第y列在tmp1宫的tmp2个格子
        	bool flag=0;
        	for(int j=1;j<=9;++j){
        		if(i==ans[row][j]&&y!=j){//行是否重复
        			flag=1;
        			break;
    			}
        		if(ans[j][y]==i&&j!=row){//列是否重复
        			flag=1;
        			break;
    			}
        		if(box[tmp1][j]==i&&j!=tmp2){//宫是否重复
        			flag=1;
        			break;
    			}
    		}
    		if(flag)continue;
            ans[row][y]=i;
            box[tmp1][tmp2]=i;
            ++use[i];
            if(y==9)dfs(x+1,1);
            else dfs(x,y+1);
            box[tmp1][tmp2]=0;
            ans[row][y]=0;
            --use[i];
        }
    else
        for(int i=9;i>=1;--i){
        	int tmp1=g[row][y],tmp2=(row-1)%3*3+(y-1)%3+1;
        	bool flag=0;
        	for(int j=1;j<=9;++j){
        		if(i==ans[row][j]&&y!=j){
        			flag=1;
        			break;
    			}
        		if(ans[j][y]==i&&j!=row){
        			flag=1;
        			break;
    			}
        		if(box[tmp1][j]==i&&j!=tmp2){
        			flag=1;
        			break;
    			}
    		}
    		if(flag)continue;
            ans[row][y]=i;
            box[tmp1][tmp2]=i;
            ++use[i];
            if(y==9)dfs(x+1,1);
            else dfs(x,y+1);
            box[tmp1][tmp2]=0;
            ans[row][y]=0;
            --use[i];
        }
}
int main(){
    memset(cntzero,-1,sizeof(cntzero));
    for(int i=1;i<=9;++i){
        cntzero[i].total=0;
        for(int j=1;j<=9;++j){
            scanf("%d",&ans[i][j]);
            box[g[i][j]].push_back(ans[i][j]);
            ++use[ans[i][j]];
            cntzero[i].total+=(ans[i][j]==0);
            //统计第i行0的数量
        }
        cntzero[i].ind=i;
    }
    sort(cntzero+1,cntzero+10,cmp);
    //优先搜索0的数量较少的行
    dfs(1,1);
    if(score!=0)printf("%d",score);
    else printf("-1");
}

回复

0 条回复,欢迎继续交流。

正在加载回复...