LA4256 UVa11552 dp状态设计

这两个题的状态表示是相似的:
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

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值