Uva1424/Uvalive 4256 Salesman商人 (简单dp)

题意:给定一个包含 n n n( n < = 100 n<=100 n<=100)个点的无向连通图和一个长度为 L L L的序列 A A A( L < = 200 L<=200 L<=200),你的任务是修改尽量少的数,使得序列中的任意两个相邻的数要么是相等的,要么是对应在图里面相邻的。
思路:要使得这个修改的数尽量少,不难发现找不到一种贪心的方法。使得数最少,考虑用 d p dp dp解决,我们用 d p i dp_i dpi来维护使得序列 A A A变得合法所需要最少的花费。
然而, d p i − 1 dp_{i-1} dpi1对应的数字是何种会影响 d p i dp_i dpi的答案,所以我们要维护多一个维度来去使得答案是最小的.
d p i , j dp_{i,j} dpi,j表示把第 i i i个数字改为 j j j而且前 i i i个序列合法的费用.
不难有以下式子:
d p i , j = m i n ( d p i − 1 , k + o k ) , 其 中 要 求 k 与 j 在 原 图 中 相 邻 , 当 i ≠ j 时 , o k = 1 , i = j 时 , o k = 0 dp_{i,j}=min(dp_{i-1,k}+ok),其中要求k与j在原图中相邻,当i\neq j时,ok=1,i=j时,ok=0 dpi,j=min(dpi1,k+ok),kji=j,ok=1,i=j,ok=0
复杂度是 O ( L ∗ n 2 ) O(L*n^2) O(Ln2),足以通过本题数据:

/*
  Uvalive 4256
  dp(i,j) 表示为把第i位改成数字j,而且前i位均合法的答案. 
  j!=i,dp(i,j)=min{dp(i-1,k) | {k与j在原图中相邻} } + 1.
  i==j,dp(i,i) = min{ dp{i-1,k) | {k与i在原图中相邻} } . 
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100+7;
const int INF = 1e9+7;
int G[maxn][maxn];
int a[2*maxn];
int dp[2*maxn][maxn];
void _init(int n){
	for(int i=0;i<=n;i++) {
		for(int j=0;j<=105;j++) dp[i][j] = INF;
	} 
}
int main(){
	int T;cin>>T;
	while(T--){
		int n,m;
		scanf("%d %d",&n,&m);
		memset(G,0,sizeof(G));
		for(int i=1;i<=m;i++){
			int u,v;scanf("%d %d",&u,&v);
			G[u][v]=G[v][u]=1;
		}
		int L;scanf("%d",&L);
		_init(L);
		for(int i=1;i<=L;i++) scanf("%d",&a[i]);
		for(int i=1;i<=n;i++) {
			dp[1][i] = (i==a[1]) ? 0 : 1;
			G[i][i]=1;
		}
		for(int i=2;i<=L;i++){
			for(int j=1;j<=n;j++){
				int ok=(!(a[i]==j));//如果a[i]==j ok=0;否则ok=1;
				for(int k=1;k<=n;k++){
				if(G[k][j]) dp[i][j] =min(dp[i][j],dp[i-1][k]+ok);
				} 
			}
		}
		int ans = INF;
		for(int i=1;i<=n;i++){
			ans=min(ans,dp[L][i]);
		}
		cout<<ans<<"\n";
	}
return 0;}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值