这两个题的状态表示是相似的:
dp[i][j]都表示第i部分放(j)可以得到的最优解。
状态转移也是相似的:
枚举前一部分和当前部分,根据二者关系转移状态。
LA 4256
题意:
给定一个包含n个点的无向连通图和一个长度为L的序列A,你的任务是修改尽量少的数,使序列中任意两个相邻数或者相同,或者对应图中相邻的两个点。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=200+9;
int g[N][N],d[N][N],s[N];
/*
d[i][j]表示第i位上的数是j,最少需要修改的数
如果第i位上的数修改了,那么d[i][j]=d[i-1][k]+1
没有修改:d[i][j]=d[i-1][k]
当然前提是第i位和第i-1位上的数相等或者相连
*/
int main() {
int T,n,m,a,b,L;
//freopen ("f.txt", "r", stdin);
scanf ("%d", &T);
while (T--) {
scanf ("%d%d", &n, &m);
memset (g,0,sizeof (g) );
for (int i=0; i<m; i++) {
scanf ("%d%d",&a,&b);
g[a][b]=g[b][a]=1;
}
scanf ("%d",&L);
for (int i=1; i<=L; i++) scanf ("%d",&s[i]);
for (int i=1; i<=n; i++) d[0][i]=0;
for (int i=1; i<=L; i++) {
for (int j=1; j<=n; j++) {
d[i][j]=INF;
for (int k=1; k<=n; k++)
if (j==k||g[j][k])
if (j==s[i]) d[i][j]=min (d[i][j],d[i-1][k]);
else d[i][j]=min (d[i][j],d[i-1][k]+1);
}
}
int ans=INF;
for (int i=1; i<=n; i++) ans=min (ans,d[L][i]);
printf ("%d\n",ans);
}
return 0;
}
/*
SampleInput
2
7 9
1 2
2 3
2 4
2 6
3 4
4 5
5 6
7 4
7 5
SampleOutput
*/
UVa 11552
题意:
给一个字符串,把它分为k块,例如字符串“helloworld”分成2块,”hello”, “world”,每一块里面的字母可以任意的排序。最终字符串, 连续的一样的字母算作一个chunk,问总chunks最少是多少?
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int INF=0x3f3f3f3f;
const int N = 1e3 + 9;
char s[N];
int f[N][N],vis[N];;
/*
f[L][i]表示第L组的末尾放第i个字符得到的最少块
如果第L-1组的最后一位和第L组的第一位是一样的,那么可以合并这两个,总chunks可以减少一个
即:
f[i][j] = min{ 如果i-1组的最后一位和i组的第一位不同: f[i-1][k]+chunks[i],
如果i-1组的最后一位和i组的第一位相同: f[i-1][k]+chunks[i]-1 }
*/
int main() {
//freopen("f.txt","r",stdin);
int T;
scanf ("%d", &T);
int k;
while (T--) {
scanf ("%d%s",&k ,s );
int n = strlen (s);
memset (f,0x3f,sizeof (f) );
for (int L=0; L<n/k; L++) {
memset (vis,0,sizeof (vis) );
for (int i=L*k; i< (L+1) *k; i++)
vis[s[i]]=1;
int cnt=0;
for (int i='a'; i<='z'; i++) cnt+=vis[i];
if (L==0) {
for (int i=0; i<k; i++) f[0][i]=cnt;
continue;
}
for (int i=0; i<k; i++) {
int rear=L*k+i;
for (int j=0; j<k; j++) {
int pre= (L-1) *k+j;
if (vis[s[pre]]&& (cnt==1||s[pre]!=s[rear]) )
f[L][i]=min (f[L][i],f[L-1][j]+cnt-1);
else f[L][i]=min (f[L][i],f[L-1][j]+cnt);
}
}
}
int ans=INF;
for (int i=0; i<k; i++)
ans=min (ans,f[n/k-1][i]);
printf ("%d\n",ans);
}
return 0;
}
/*
SampleInput
2
5 helloworld
7 thefewestflops
SampleOutput
8
10
*/