CodeForces 1407E : Egor in the Republic of Dagestan 最短路 + 染色

传送门

题目描述

n n n 个点 m m m 条边的无向图,边有黑白两种颜色。现在要给点染色,每个点染成黑或白色。白点只能走它连出去的白边,黑点只能走它连出去的黑边。问是否存在一种染色方案,使得不存在一条 1 → n 1\rightarrow n 1n 的路径。如果不存在,在第一行输出 -1,否则输出 1 → n 1\rightarrow n 1n 最长的最短路径长度。在第二行,输出对应第一行答案的染色方案。

分析

这个图论比较裸了
我们可以从重点开始反向搜索,把所有能走的边尽量的都去封死
这样就会产生两种情况,一个点即被黑色边又被白色边链接,那么这种情况下,这个点就是必须要经过的点,需要加入队列中计算最短路
其余情况下的点都可以通过染色被删去

代码

#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
int gcd(int a,int b){return (b>0)?gcd(b,a%b):a;}
int h[N],e[N],ne[N],w[N],idx;
int d[N];
int col[N];
bool st[N];
int n,m;

void add(int x,int y,int z){
	ne[idx] = h[x],e[idx] = y,w[idx] = z,h[x] = idx++;
}

int main(){
    read(n),read(m);
  	memset(h,-1,sizeof h);
  	while(m--){
  		int x,y,z;
  		read(x),read(y),read(z);
  		add(y,x,z);
  	}
  	if(n == 1){
  		printf("0 0");
  		return 0;
  	}
  	memset(col,-1,sizeof col);
  	queue<int> q;
  	q.push(n);
  	st[n] = 1;
  	while(q.size()){
  		int t = q.front();
  		if(t == 1) break;
  		q.pop();
  		for(int i = h[t];~i;i = ne[i]){
  			int j = e[i];
  			if(st[j]) continue;
  			if(col[j] == -1 || col[j] == 1 - w[i]) col[j] = 1 - w[i];
  			else{
  				d[j] = d[t] + 1;
  				st[j] = 1;
  				q.push(j);
  			}
  		}
  	}
  	if(st[1]) printf("%d\n",d[1]);
  	else puts("-1");
  	
  	for(int i = 1;i <= n;i++) if(col[i] == -1) printf("0");
  		else printf("%d",col[i]);
  	return 0;
}

/**
*  ┏┓   ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃       ┃
* ┃   ━   ┃ ++ + + +
*  ████━████+
*  ◥██◤ ◥██◤ +
* ┃   ┻   ┃
* ┃       ┃ + +
* ┗━┓   ┏━┛
*   ┃   ┃ + + + +Code is far away from  
*   ┃   ┃ + bug with the animal protecting
*   ┃    ┗━━━┓ 神兽保佑,代码无bug 
*   ┃        ┣┓
*    ┃        ┏┛
*     ┗┓┓┏━┳┓┏┛ + + + +
*    ┃┫┫ ┃┫┫
*    ┗┻┛ ┗┻┛+ + + +
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值