关于DP进阶题

探讨在给定城市和单向传送门条件下,如何避免特定城市并找到从城市1到城市N的最短路径,涉及路径搜索算法。

[ABC291F] Teleporter and Closed off - 洛谷

有 �N 个城市,编号为 1,2,…,�1,2,…,N。还有单向传送门,可以将你传送到不同的城市。一个传送门是否可以直接从城市 �i (1≤�≤�)(1≤i≤N) 传送到另一个城市,由长度为 �M 的字符串 ��Si​ 表示。

具体来说,对于 1≤�≤�1≤j≤N,如果 1≤�−�≤�1≤j−i≤M 并且 ��Si​ 的第 (�−�)(j−i) 个字符是1,则传送门可以直接从城市 �i 传送到城市 �j;否则,它不能直接从城市 �i 传送到城市 �j。对于 �=2,3,…,�−1k=2,3,…,N−1,

解决以下问题:
你能否在不经过城市 �k 的情况下从城市 11 到达城市 �N,反复使用传送门?如果可以,打印出你需要使用传送门的最小次数;否则,打印出 −1−1。

There are �N cities numbered city 11, city 22, ……, and city �N.
There are also one-way teleporters that send you to different cities. Whether a teleporter can send you directly from city �i (1≤�≤�)(1≤i≤N) to another is represented by a length-�M string ��Si​ consisting of 0 and 1. Specifically, for 1≤�≤�1≤j≤N,

  • if 1≤�−�≤�1≤j−i≤M and the (�−�)(j−i)-th character of ��Si​ is 1, then a teleporter can send you directly from city �i to city �j;
  • otherwise, it cannot send you directly from city �i to city �j.

Solve the following problem for �=2,3,…,�−1k=2,3,…,N−1:

Can you travel from city 11 to city �N without visiting city �k by repeatedly using a teleporter? If you can, print the minimum number of times you need to use a teleporter; otherwise, print −1−1.

Constraints

  • 3≤�≤1053≤N≤105
  • 1≤�≤101≤M≤10
  • �<�M<N
  • ��Si​ is a string of length �M consisting of 0 and 1.
  • If �+�>�i+j>N, then the �j-th character of ��Si​ is 0.
  • �N and �M are integers.

Input

The input is given from Standard Input in the following format:

�N �M
�1S1​
�2S2​
⋮⋮
��SN​

Output

Print (�−2)(N−2) integers, separated by spaces, in a single line. The �i-th (1≤�≤�−2)(1≤i≤N−2) integer should be the answer to the problem for �=�+1k=i+1.

Sample 1

InputcopyOutputcopy
5 2
11
01
11
10
00
2 3 2

A teleporter sends you

  • from city 11 to cities 22 and 33;
  • from city 22 to city 44;
  • from city 33 to cities 44 and 55;
  • from city 44 to city 55; and
  • from city 55 to nowhere.

Therefore, there are three paths to travel from city 11 to city 55:

  • path 11 : city 11 →→ city 22 →→ city 44 →→ city 55;
  • path 22 : city 11 →→ city 33 →→ city 44 →→ city 55; and
  • path 33 : city 11 →→ city 33 →→ city 55.

Among these paths,

  • two paths, path 22 and path 33, do not visit city 22. Among them, path 33 requires the minimum number of teleporter uses (twice).
  • Path 11 is the only path without city 33. It requires using a teleporter three times.
  • Path 33 is the only path without city 44. It requires using a teleporter twice.

Thus, 22, 33, and 22, separated by spaces, should be printed.

Sample 2

InputcopyOutputcopy
6 3
101
001
101
000
100
000
-1 3 3 -1

The only path from city 11 to city 66 is city 11 →→ city 22 →→ city 55 →→ city 66.
For �=2,5k=2,5, there is no way to travel from city 11 to city 66 without visiting city �k.
For �=3,4k=3,4, the path above satisfies the condition; it requires using a teleporter three times.

Thus, −1−1, 33, 33, and −1−1, separated by spaces, should be printed.

Note that a teleporter is one-way; a teleporter can send you from city 33 to city 44, but not from city 44 to city 33,
so the following path, for example, is invalid: city 11 →→ city 44 →→ city 33 →→ city 66.

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+11,inf = 1e9+7;
int n,m;
string a[maxn];
int f[maxn],g[maxn];
bool check(int i,int j){
	int dis = j-i;
	if(j-i>m)return 0;
	if(a[i][dis] == '1')return 1;
	return 0;
}
int main(){
	memset(f,0x3f,sizeof(f));
	memset(g,0x3f,sizeof(g));
	cin>>n>>m;
	for(int i = 1;i <= n;i++){
		cin>>a[i];
		a[i] = " "+a[i];
	}
	f[1] = 0;
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= m;j++){
			int to = i+j; 
			if(a[i][j] =='1'){
				f[to] = min(f[to],f[i]+1);
			}
		} 
	}
	g[n] = 0;
    for(int i = n;i >= 1;i--){
		for(int j = 1;j <= m;j++){
			int to = i-j; 
			if(to <= 0)continue;
			if(a[to][j] =='1'){
				g[to] = min(g[to],g[i]+1);
			}
		} 
	}
	for (int k = 2; k <= n-1; k++) {
		int ans = inf;
        for (int l =  max(1,k-m);l < k;l++){
        	for(int r = k+1;r <= min(n,k+m);r++){
                if(check(l,r))ans = min(ans,f[l]+g[r]+1);
			}
		} 
		if(inf == ans)cout<<-1<<" ";
		else cout<<ans<<" "; 
    }
	return 0;
}

 Hot Start Up (easy version) - 洛谷

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5010;
long long dp[maxn][maxn],a[maxn],hot[maxn],cold[maxn];
void slove(){
	int n,k;
	cin>>n>>k;
	for(int i = 1;i <= n;i++){
		cin>>a[i];
	}
	for(int i = 1;i <= k;i++){
		cin>>cold[i];
	}
	for(int i = 1;i <= k;i++){
		cin>>hot[i];
	}
	for(int i = 0;i <= n;i++){
		for(int j = 0;j <= k;j++){
			dp[i][j] = 1e18;
		}
	}
	a[0] = -1;
	dp[1][0] = cold[a[1]];
	for(int i = 2;i <= n;i++){
		int first = a[i-1];
		for(int j = 0;j <= k;j++){
			dp[i][j] = min(dp[i][j],dp[i-1][j]+(a[i] == first?hot[a[i]]:cold[a[i]]));
			dp[i][first] = min(dp[i][first],dp[i-1][j]+(a[i] == j?hot[a[i]]:cold[a[i]]));
		}
	}
	long long ans = 1e18;
	for(int i = 0;i <= k;i++){
	    ans = min(ans,dp[n][i]);
	}
	cout<<ans<<endl;
}
int main(){
//memset(f,0x3f,sizeof(f));
    int t;
    cin>>t;
    while(t--){
    	slove();
	}

}

Hot Start Up (hard version) - 洛谷

#include<bits/stdc++.h>
using namespace std;
const int maxn = 305010;
long long dp[maxn],a[maxn],hot[maxn],cold[maxn];
long long sum[maxn];
void slove(){
	int n,k;
	cin>>n>>k;
	for(int i = 1;i <= n;i++){
		cin>>a[i];
	}
	for(int i = 1;i <= k;i++){
		cin>>cold[i];
	}
	for(int i = 1;i <= k;i++){
		cin>>hot[i];
		dp[i] = 1e18;
	}
	dp[0] = 0;
	long long s = 0,mindp = 0;
	for(int i = 1;i <= n;i++){
		if(a[i] == a[i-1]){
			s += hot[a[i]];
		}
		else{
			s += cold[a[i]];
			dp[a[i-1]] = min(dp[a[i]]+hot[a[i]],mindp+cold[a[i]])-cold[a[i]];
			mindp = min(mindp,dp[a[i-1]]);
		}
	}
	cout<<s+mindp<<endl;
}
int main(){
//memset(f,0x3f,sizeof(f));
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--){
    	slove();
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值