Live2D

CF1149D Abandoning Roads

link

Solution

可以看出的是,a 边所形成的连通块是固定的,然后 b 边的作用是把这些连通块串起来。

那么一条路径合法当且仅当不存在从一个 a 连通块通过 b 边出去然后又回来。正确性显然。

那么我们可以考虑一个暴力 dp 即是 \(f_{S,u}\) 表示已经走过了 \(S\) 这个集合里的 a 连通块,当前在 \(u\) 的最小代价。可以发现这个东西可以用最短路优化。

但是 \(n\le 70\),显然需要进一步的优化。可以看出的是,对于 \(\le 3\) 的 a 连通块,最优策略不可能走出去再走回来,因为这样至少需要 \(2\) 条 b 边,但是你在 a 连通块内最多也就走 \(2\) 条 a 边,所以我们最多只有 \(\lfloor\frac{n}{4}\rfloor\) 个连通块,就可以做了。

似乎做完之后再看就不是很难,可以一旦自己做就什么都想不到了?/kk

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 205

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,m,A,B,tot,fa[MAXN];
int findSet (int x){return fa[x] == x ? x : fa[x] = findSet (fa[x]);}

struct edge{
	int u,v;
}s[MAXN];
vector <int> g[MAXN],H[MAXN];

vector <int> Seq;
bool vis[1 << 17][MAXN];
int cnt,ind[MAXN],tur[MAXN],bak[MAXN],siz[MAXN],dis[1 << 17][MAXN];

#define pii pair<int,int>
#define se second
#define fi first

struct node{
	int dis,Sta,pos;
	bool operator < (const node &p)const{return dis > p.dis;}
};

void Dijkstra (){
	int sta = bak[ind[findSet (1)]] ? (1 << bak[ind[findSet (1)]] - 1) : 0;
	priority_queue <node> q;memset (dis,0x3f,sizeof (dis)),dis[sta][1] = 0,q.push (node{0,sta,1});
	while (!q.empty()){
		node it = q.top();q.pop ();
		int Sta = it.Sta,u = it.pos,d = it.dis;
		if (vis[Sta][u] || d != dis[Sta][u]) continue;
		vis[Sta][u] = 1;
		for (Int v : H[u]){
			if (dis[Sta][v] > dis[Sta][u] + A){
				dis[Sta][v] = dis[Sta][u] + A;
				if (!vis[Sta][v]) q.push (node{dis[Sta][v],Sta,v});
			}
		}
		for (Int v : g[u]){
			int nid = bak[ind[findSet (v)]],nSta = nid ? (Sta | (1 << nid - 1)) : Sta;
			if (nid && (Sta >> nid - 1 & 1)) continue;
			if (findSet (v) == findSet (u)) continue;
			if (dis[nSta][v] > dis[Sta][u] + B){
				dis[nSta][v] = dis[Sta][u] + B;
				if (!vis[nSta][v]) q.push (node{dis[nSta][v],nSta,v});
			}
		}
	}
}

signed main(){
	read (n,m,A,B);
	for (Int x = 1;x <= n;++ x) fa[x] = x;
	for (Int i = 1;i <= m;++ i){
		int u,v,w;read (u,v,w);
		if (w == A) s[++ tot] = edge{u,v},H[u].push_back (v),H[v].push_back (u);
		else g[u].push_back (v),g[v].push_back (u);
	}
	for (Int i = 1;i <= tot;++ i){
		int u = s[i].u,v = s[i].v;
		if (findSet (u) == findSet (v)) ;
		else fa[fa[u]] = fa[v];
	}
	for (Int u = 1;u <= n;++ u) if (fa[u] == u) ind[u] = ++ cnt,tur[cnt] = u;
	for (Int u = 1;u <= n;++ u) siz[ind[findSet (u)]] ++;
	for (Int i = 1;i <= cnt;++ i) if (siz[i] >= 4) Seq.push_back (i),bak[i] = Seq.size();
	Dijkstra ();
	for (Int i = 1;i <= n;++ i){
		int ans = 1e9;
		for (Int S = 0;S < (1 << Seq.size());++ S) chkmin (ans,dis[S][i]);
		write (ans),putchar (' ');
	}
	putchar ('\n');
	return 0;
}
posted @ 2022-10-18 11:32  Dark_Romance  阅读(60)  评论(0编辑  收藏  举报