副本dp

来源:互联网 发布:app数据接口怎么写 编辑:程序博客网 时间:2024/04/19 23:28

NO.1

 

A - HaHa's Morning

状压dp

HaHa is so happy today, he is going to participate the 7th Hunan University Programming Contest. He woke up in the morning, and wanted to reach Hunan University as soon as possible, but he realized that he still has N things to do before going on his journey.
At first, HaHa thought there must have N! (The factorial of N) ways to get everything done, however, he soon found that this was impossible at all, for the work has some annoying restrictions: some things must be done before getting some other things done. Now HaHa is interested in the number of ways to get everything done, and he asks you for help, so your task is to find how many ways are there to finish his work.
Input
There are several test cases, each case contains several lines, and the first line of each case is two natural numbers N (that described above) and M ≤ 400 (for the total restrictions for the work).
The next M lines describes the restrictions, for each line, there is two positive integers A, B, for the A-th thing must be done before the B-th thing.
The input will finish with the end of file, input is guaranteed that 1 ≤ A, B ≤ N ≤ 17.
Output
For each the case, output one number: the ways to finish the work.
Sample Input
3 21 32 32 21 22 1
Sample Output

20

题意:

这个题目就是问你把n个数按照他给的排列顺序排好,一共有多少种排法

即:一个N个点的有向图,有M条有向边,问你拓扑排序可行的方式有多少种。





题解  ooo:

对于一个点i来讲,如果其所有儿子节点都排列成功了,那么这个点也就排列成功了。

那么设定dp【i】表示排列成功的状态为i所可行的方案数个数。

那么就有Dp【q】+=dp【v】,q=v+(1<<i);

其中需要满足v&son[i]==son[i]&&v&(1<<i)==0.(当前点i的儿子都排列完了,这个点才能进行排列);


#include <iostream>#include<cstring>#include<string>#include<algorithm>#include<cstdio>using namespace std;const int maxn=1<<18;long long  dp[maxn];int son[20];int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        memset(son,0,sizeof(son));///别忘了        for(int i=0;i<m;i++)        {            int x,y;            scanf("%d%d",&x,&y);            x--; y--;            son[x]|=(1<<y);///每一位数的后节点 储存在二进制的y位        }        memset(dp,0,sizeof(dp));        dp[0]=1;        for(int i=0;i<(1<<n);i++)        {            for(int j=0;j<n;j++)            {                if((i&son[j])==son[j])///如果这种方案里面包含j的所有儿子                {                    if((i&(1<<j))==0)///并且j本身不在i方案里面                    {                        dp[(i|(1<<j))]+=dp[i];///这种方案加到带j的后来的大方案里面                    }                }            }        }        printf("%lld\n",dp[(1<<n)-1]);///输出最后答案    }    return 0;}




B - String painter

hdu(2476)  区间dp

There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other character you want. That is, after using the painter, the segment is made up of only one kind of character. Now your task is to change A to B using string painter. What’s the minimum number of operations?

Input
Input contains multiple cases. Each case consists of two lines:
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.
Output
A single line contains one integer representing the answer.
Sample Input
zzzzzfzzzzzabcdefedcbaababababababcdcdcdcdcdcd
Sample Output
67


还是看题解过的,等自己a出来的那天

题意是说:

给你两个字符串,A和B,每一次我们可以使用一种颜色(用字母代替)刷任意位子的连续子序列,问将字符串A变成字符串B最少需要刷多少次。


关于思路,参考博客here:

1.先刷出一个b来,不考虑a,看刷出一个b最少需要多少笔(区间dp):

    状态转移是

     dp[i][j]  有四种刷法  :

       (1)从刷好的 i+1 - > j,然后从 i+1 往前刷到 i,如果 i+1 和 i 相同的话,直接刷,否则需要多刷一笔: dp[i+1][j]+oj(i,i+1);

       (2)从刷好的 i+1 - > j,然后从 j 往前刷到 i,如果 i 和 j 相同的话,直接刷,否则需要多刷一笔: dp[i+1][j]+oj(i,j);

       (3)从刷好的 i - > j-1,然后从 j-1 往前刷到 i,如果 j 和 j-1相同的话,直接刷,否则需要多刷一笔: dp[i][j-1]+oj(j,j-1);

       (4)从刷好的 i - > j-1,然后从 i 往后刷到 j,如果 i 和 j 相同的话,直接刷,否则需要多刷一笔: dp[i][j-1]+oj(i,j);

    然后从区间 i 到 j 里面选择一个,断开刷比较大小

2. 然后看a 串,对于每位a 它可以有dp【0】【i】种刷法,但是如果此位a与b相同,可以省去一次刷,所以进行比较,

如果a【i】==b【i】 那么当前f【i】可以试于前一个f【i-1】相同;

否则,单独刷成,更新寻找最小值;


代码::::::--------------------------------------------------》》》》》》》》》》》》

#include <iostream>#include<algorithm>#include<cstring>#include<string>#include<cstdio>#include<valarray>using namespace std;const int maxn=200+5;const int inf=0x3f3f3f3f;int dp[maxn][maxn];int f[maxn];string a,b;int ju(int i,int j){    if(b[i]==b[j])        return 0;    else        return 1;}int main(){    while(cin>>a>>b)    {        int n=a.size();        memset(dp,inf,sizeof(dp));       for(int l=1;l<=n;l++)       {           for(int i=0;i+l<=n;i++)           {               int j=i+l-1;               if(l==1)               {                   dp[i][j]=1;               }               if(i+1<n) dp[i][j]=min(dp[i][j],dp[i+1][j]+ju(i,i+1));               if(i+1<n) dp[i][j]=min(dp[i][j],dp[i+1][j]+ju(i,j));               if(j-1>=0) dp[i][j]=min(dp[i][j],dp[i][j-1]+ju(j,j-1));               if(j-1>=0) dp[i][j]=min(dp[i][j],dp[i][j-1]+ju(i,j));               for(int k=i;k<j;k++)               {                   dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);               }           }       }       for(int i=0;i<n;i++)       {           f[i]=dp[0][i];           if(a[i]==b[i]) f[i]=f[i-1];           else           {               for(int j=0;j<i;j++)                f[i]=min(f[i],f[j]+dp[j+1][i]);           }       }       cout<<f[n-1]<<endl;    }    return 0;}






原创粉丝点击