拓扑样例不过求助,详细注释
查看原帖
拓扑样例不过求助,详细注释
678087
fangzichang楼主2023/5/1 11:12

rt,手推的不知道对不对
代码略长。 常数肯定大,但是现在连正确都做不到就先不管了。 悬1关注找错,若您愿意帮调再加1关。

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<bits/stdc++.h>
#define x first
#define y second
#define ll long long
#define Inf (int)IFINITY
#define inf 0x3f3f3f3f3f
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define unordered_map __gnu_pbds::gp_hash_table//好习惯 
#define pb push_back
using namespace std;
inline void read(int &x){
	x=0;bool f=0;char c=getchar();
	while(c>'9'||c<'0'){f=c=='-';c=getchar();}
	while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
	if(f) x=-x;
//    cin>>x;
}
#define cin(x) read(x)
const int M=15;
const int N=1e7+10;
const int fx[]={0,1,0,-1};
const int fy[]={1,0,-1,0};
struct zt{//存状态 
    bool f;//0红1黑在走 
    int r1x,r1y,r2x,r2y,bx,by;
    void build(bool F,int R1x,int R1y,int R2x,int R2y,int Bx,int By){
    	f=F;
		r1x=R1x;r1y=R1y;
		r2x=R2x;r2y=R2y;
		bx=Bx;by=By;
	}
    bool out(){//黑棋走到第一行 
        return bx==1;
    }
    bool eat(){//红黑存在重叠 
        return (r1x==bx&&r1y==by)||
               (r2x==bx&&r2y==by);
    }
    bool operator==(const zt&y)const{//判相等,unmap要用 
    	return f==y.f&&
			   r1x==y.r1x&&r1y==y.r1y&&
			   r2x==y.r2x&&r2y==y.r2y&&
			   bx==y.bx&&by==y.by;
	}
};
struct myhash{//自定义哈希函数,不清楚是不是这里的问题 
    static uint64_t splitmix64(uint64_t x){
        x+=0x9e3779b97f4a7c15;
        x=(x^(x>>30))*0xbf58476d1ce4e5b9ll;
        x=(x^(x>>27))*0x94d049bb133111ebll;
        return x^(x>>31);
    }
    size_t operator()(uint64_t x)const{
        static const uint64_t FIXED_RANDOM=chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x+FIXED_RANDOM);
    }
    size_t operator()(zt x)const{
        static const uint64_t FIXED_RANDOM=chrono::steady_clock::now().time_since_epoch().count();
        return (splitmix64(x.bx+FIXED_RANDOM)^(splitmix64(x.by+FIXED_RANDOM)>>1)<<1)^
               (splitmix64(x.r1x+FIXED_RANDOM)^(splitmix64(x.r1y+FIXED_RANDOM)>>1)<<1)^
               (splitmix64(x.r2x+FIXED_RANDOM)^(splitmix64(x.r2y+FIXED_RANDOM)>>1)<<1);
    }
};
zt st;//初始状态 
unordered_map<char,int> val;//字符转数字 
unordered_map<zt,int,myhash> f;//对状态进行编号 
int id,T,n,m,cnt;//cnt表示状态编号总数 
int a[M][M];//地图 
int dp[N],win[N],in[N];//dp就是状态所需步数,win是胜负(0当前先手输/平局,1当前先手赢),in是入度 
bool flg=0;
int get(int x,int y){//坐标转数字 
	return (x-1)*m+y;
}
pii _get(int x){//数字转坐标 
	int y=x%m;
	x-=y;
	x=x/m+1;
	return {x,y};
}
vector<int> nxt[N];//建图 
deque<int> q;//拓扑的队列 
void dfs(zt x){//dfs求能到达的状态 
    if(f[x]) return;
    f[x]=++cnt;//编号 
    #ifdef debug
    cout<<cnt<<endl;
    #endif
    if(x.f==1){
	    if(x.eat()){//有吃子的结束状态
	    	q.pb(f[x]);//加入队列 
	        return;
		}
		bool flg=0;
        for(int i=0;i<3;i++){//不能往下走 
        	zt y=x;
        	y.f^=1;
        	y.bx+=fx[i],y.by+=fy[i];
        	if(y.bx<=0||y.bx>n||y.by<=0||y.by>m||a[y.bx][y.by]==-1) continue;//出界或者障碍 
        	else{
        		flg=1;//标记黑方能走 
        		dfs(y);
        		nxt[f[y]].pb(f[x]);//反向建图 
        		in[f[x]]++;
			}
		}
		if(!flg){//黑方不能走就输了,红赢 
	    	q.pb(f[x]);
	        return;			
		}
    }
    else{
	    if(x.out()||x.eat()){//现在是红方走,那黑方到第一行或者有吃子就是黑赢 
	    	q.pb(f[x]);
	        return;
	    }	    
		bool flg=0;	
        for(int i=0;i<4;i++){
        	zt y=x;
        	y.f^=1;
        	y.r1x+=fx[i],y.r1y+=fy[i];
        	if(y.r1x<=0||y.r1x>n||y.r1y<=0||y.r1y>m||a[y.r1x][y.r1y]==-1||(y.r1x==y.r2x&&y.r1y==y.r2y)) continue;//判出界和障碍和红子相撞 
        	else{
				flg=1;//红方能动 
        		dfs(y);
        		nxt[f[y]].pb(f[x]);//反向建图 
        		in[f[x]]++;
			}
		} 
        for(int i=0;i<4;i++){
        	zt y=x;
        	y.f^=1;
        	y.r2x+=fx[i],y.r2y+=fy[i];
        	if(y.r2x<=0||y.r2x>n||y.r2y<=0||y.r2y>m||a[y.r2x][y.r2y]==-1||(y.r1x==y.r2x&&y.r1y==y.r2y)) continue;//判出界和障碍和红子相撞 
        	else{
        		flg=1;//红方能动 
        		dfs(y);
        		nxt[f[y]].pb(f[x]);//反向建图 
        		in[f[x]]++;
			}
		} 	
		if(!flg){//红方不能走就输了,黑赢 
	    	q.pb(f[x]);
	        return;
		}	
	}
}
void topsort(){
	while(!q.empty()){
		int u=q.front();q.pop_front();
		if(u==1){//走到开始的状态 
			flg=1;//标记走得到起点 
			break;
		}
		for(int v:nxt[u]){
			in[v]--;
			if(!win[u]){//当前状态u是先手输/平局 
				if(!win[v]){//能到这个状态的v被判定为先手输/平局 
					win[v]=1;//能到这个状态的v被覆盖为先手赢 
					dp[v]=dp[u]+1;//步数刷新 
					q.pb(v);
				}
				else{//能到这个状态的v被判定为先手赢
					dp[v]=min(dp[v],dp[u]+1);//刷新最小步数 
				}
			}
			else{//当前状态u是先手赢
				if(!win[v]){//当前状态v是先手输/平局 
					dp[v]=max(dp[v],dp[u]+1);//刷新最大步数 
				}				
			}
			if(in[v]==0){
				q.pb(v);
			}
		}
	}
}
void init(){
	for(int i=1;i<N;i++) win[i]=dp[i]=in[i]=0,nxt[i].clear();
    int rid1=0,rid2=0,bid=0;
    f.clear();
    q.clear();
    flg=0,cnt=0;//初始化 
    cin(n),cin(m);
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        s='%'+s;
        for(int j=1;j<=m;j++){
            char c=s[j];
            a[i][j]=val[c];
            if(val[c]==1){
                if(rid1) rid2=get(i,j);
                else rid1=get(i,j);
            }
            else if(val[c]==2){
                bid=get(i,j);
            }
        }
    }
    st.build(0,_get(rid1).x,_get(rid1).y,_get(rid2).x,_get(rid2).y,_get(bid).x,_get(bid).y);//起始状态 
}
signed main(){
    val['.']=0;
    val['#']=-1;
    val['O']=1;
    val['X']=2;
    cin(id);
    cin(T);  
    while(T--){
        init();
        dfs(st);
        topsort();
        if(!flg){//走不到起点为平局 
        	puts("Tie");
		}
		else if(win[1]){//先手赢就是红方赢 
			printf("Red %d\n",dp[1]);
		}
		else{
			printf("Black %d\n",dp[1]);
		}
    }
    return 0;
}
/*
0 1
3 3
O..
.#X
.O.
*/
2023/5/1 11:12
加载中...