题目:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=68677#problem/C
题意:
给出一个无向图,给出一段序列,要求修改最少的次数,使序列中的相邻两个有直接通路,求出最少修改的点.
思路:
DP,
状态方程: dp[i][j] = min(dp[i][j], dp[i-1][k] + 1). 如果j与k之间有通路,若i位置需要修改成j,且从i-1位置的k点到i位置的j点(i位置上的点不等于j).
dp[i][j] = min(dp[i][j], dp[i-1][k] ).如果j与k之间没有通路.
注意从t点到t点也相当于有通路.
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int INF = 250;
int n, m, s;
int a[105][105], num[205], dp[205][105];
void init()
{
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= s; ++i) {
for(int j = 1; j <= n; ++j) {
dp[i][j] = INF;
}
}
}
int main()
{
//freopen("in", "r", stdin);
int T;
scanf("%d", &T);
while(T--) {
memset(a, 0, sizeof(a));
scanf("%d %d", &n, &m);
for(int i = 0; i < m; ++i) {
int x, y;
scanf("%d %d", &x, &y);
a[x][y] = 1;
a[y][x] = 1;
}
for(int i = 1; i <= n; ++i) a[i][i] = 1;
scanf("%d", &s);
init();
for(int i = 1; i <= s; ++i) {
scanf("%d", &num[i]);
}
for(int i = 1; i <= s; ++i) {
for(int j = 1; j <= n; ++j) {
for(int k = 1; k <= n; ++k) {
if(a[j][k] || i==1) {
if(num[i] != j)
dp[i][j] = min(dp[i][j], dp[i-1][k]+1);
else
dp[i][j] = min(dp[i][j], dp[i-1][k]);
}
}
}
}
int ans = INF;
for(int i = 1; i <= n; ++i) {
//printf("%d ", dp[s][i]);
ans = min(ans, dp[s][i]);
}
printf("%d\n", ans);
}
return 0;
}