UVALive

来源:互联网 发布:广东问政网络平台 编辑:程序博客网 时间:2024/06/09 18:28

题意:给定一个包含n(n <= 100)个点的无向联通图和一个长度为L的序列A(L <= 200),你的任务是修改尽量少的数,使得序列中的任意两个相邻数或者相同,或者对应图中的两个相邻节点。

思路:用dp[i][j]表示从1到位置i以j为结尾的最小修改的数,则答案为max(dp[L][1~n]).

如果a[i] == j, dp[i][j] = min(dp[i - 1][j], dp[i - 1][k]) 。否则dp[i][j] = min(dp[i - 1][j] + 1, dp[i - 1][k] + 1)  j与k为相邻节点。

#include <cstdio>#include <algorithm>#include <iostream>#include<vector>#include<cmath>#include<set>#include<cstring>#include<map>using namespace std;const int maxn = 21e2 + 10;const int maxt = 100200;const int INF = 0x3f3f3f3f;const int mod = 1e9 + 7;const double pi = acos(-1.0);const double eps = 1e-8;typedef long long ll;vector<int> g[110];int dp[210][110];int a[220];void init(){    for(int i = 1; i <= 100; ++i) g[i].clear();    memset(dp, INF, sizeof dp);}int main(){    int T;    scanf("%d", &T);    while(T--){        int n, m;        init();        scanf("%d%d", &n, &m);        for(int i = 0; i < m; ++i){            int x, y;            scanf("%d%d", &x, &y);            g[x].push_back(y);            g[y].push_back(x);        }        int l;        scanf("%d", &l);        for(int i = 1; i <= l; ++i)            scanf("%d", &a[i]);        dp[1][a[1]] = 0;        for(int i = 2; i <= l; ++i){            for(int j = 1; j <= n; ++j){                if(j == a[i])                    dp[i][j] = dp[i - 1][j];                else                    dp[i][j] = dp[i - 1][j] + 1;                for(int k = 0; k < g[j].size(); ++k){                    int u = g[j][k];                    if(j == a[i])                        dp[i][j] = min(dp[i][j], dp[i - 1][u]);                    else                        dp[i][j] = min(dp[i][j], dp[i - 1][u] + 1);                }            }        }        int ans = INF;        for(int i = 1; i <= n; ++i) ans = min(ans, dp[l][i]);        printf("%d\n", ans);    }}


1 0
原创粉丝点击