这道题,对于小数据,直接上爆搜,也就是把每个点所有能到的地方都用vector存一下,当0的时候,任意选点,之后再从所有能到的地方选点。因为第一问数据非常小,所以算法合格
但是第二问数据比较大,可以采用贪心算法(没有证明正确性,但是跑过了所有数据),在上面的前提下,每次选点都从合法范围最大的点出发
从直觉上来看,这样确实能够有更多的选择性和容错率,但是没有证明他的正确性。
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<algorithm> #include<queue> #include<set> #define ull unsigned long long using namespace std; typedef long long ll; typedef pair<int,int> pll; typedef pair<int,pair<int,int> > plll; const int N=1e5+10; const int inf=0x3f3f3f3f; vector<pll> g[300][300]; vector<pll> ans; int st[301][301]; int flag[301][301]; int px[N],py[N]; bool dfs(int depth,int x,int y,int n,int m){ int i; if(depth==n*m){ for(i=0;i<n*m;i++){ ans.push_back(pll{px[i],py[i]}); } return true; } if(depth==0){ for(int i=1; i <=n;i++) for (int j =1; j<=m;j++){ flag[i][j] = true; px[0] = i; py[0] = j; if(dfs(1, i, j, n, m)) return true; flag[i][j] = false; } } else{ pair<int,pll> mov[10010]; int idx=0; for(i=0;i<g[x][y].size();i++){ int u=g[x][y][i].first; int v=g[x][y][i].second; if(!flag[u][v]) mov[idx++]=make_pair(st[u][v],pll{u,v}); } sort(mov,mov+idx); for(i=0;i<idx;i++){ int u=mov[i].second.first; int v=mov[i].second.second; int j; flag[u][v]=1; px[depth]=u; py[depth]=v; for(j=0;j<g[u][v].size();j++){ int a=g[u][v][j].first; int b=g[u][v][j].second; st[a][b]--; } if(dfs(depth+1,u,v,n,m)) return true; for(j=0;j<g[u][v].size();j++){ int a=g[u][v][j].first; int b=g[u][v][j].second; st[a][b]++; } flag[u][v]=0; } } return false; } int main(){ int t; cin>>t; int cnt=0; while(t--){ cnt++; int r,c; cin>>r>>c; ans.clear(); memset(st,0,sizeof st); memset(flag,0,sizeof flag); int i,j; int x,y; for(i=1;i<=r;i++){ for(j=1;j<=c;j++){ g[i][j].clear(); for(x=1;x<=r;x++){ for(y=1;y<=c;y++){ if(i!=x&&j!=y&&i-j!=x-y&&i+j!=x+y){ g[i][j].push_back(pll{x,y}); st[i][j]++; } } } } } printf("Case #%d: ",cnt); if(!dfs(0,-1,-1,r,c)){ cout<<"IMPOSSIBLE"<<endl; } else{ cout<<"POSSIBLE"<<endl; for(i=0;i<ans.size();i++){ cout<<ans[i].first<<" "<<ans[i].second<<endl; } } } }