LA 4256 Salesmen

来源:互联网 发布:售电软件 编辑:程序博客网 时间:2024/05/01 04:26

题意:给出n个点的无向图,再给出一个序列,尽量修改少的数,令序列中任意相邻的两个数相同或者是图中的两个相邻结点。

思路:用dp[i][j]表示将第i个数字改成j,前i个序列所需要的最少修改次数。那么很容易得到状态转移方程:dp[i][j]=min(dp[i][j],dp[i-1][k]+(j==num[i]?:0:1))。其中dp[i-1][k]代表将第i-1个数修改成k所需要的最少修改次数,要注意的是j和k要么相等,要么在图中是相连的两个结点。

 

代码:

 

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<set>#include<stack>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-9#define pi acos(-1.0)using namespace std;typedef long long ll;const int maxn=100+10;int a[maxn][maxn];int dp[maxn<<1][maxn];int num[maxn<<1];int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int t;    scanf("%d",&t);    while(t--)    {        int n,m,x,y;        scanf("%d%d",&n,&m);        memset(a,0,sizeof(a));        memset(dp,0xff,sizeof(dp));        for(int i=0;i<m;++i)        {            scanf("%d%d",&x,&y);            a[x][y]=a[y][x]=1;        }        for(int i=1;i<=n;++i) a[i][i]=1;        int z;        scanf("%d",&z);        for(int i=1;i<=z;++i)           scanf("%d",&num[i]);        for(int i=1;i<=n;++i) dp[1][i]=1;        dp[1][num[1]]=0;        for(int i=2;i<=z;++i)        {            for(int j=1;j<=n;++j)            {                for(int k=1;k<=n;++k)                {                    if(a[k][j]&&dp[i-1][j]!=-1)                    {                        if(dp[i][j]==-1)                           dp[i][j]=dp[i-1][k]+(j==num[i]?0:1);                        else                           dp[i][j]=min(dp[i][j],dp[i-1][k]+(j==num[i]?0:1));                    }                }            }        }        int ans=inf;        for(int i=1;i<=n;++i)           if(dp[z][i]!=-1) ans=min(ans,dp[z][i]);        printf("%d\n",ans);    }    return 0;}


 

原创粉丝点击