• dp练习


    1013 Battle Over Cities

    原来的图不一定连通,所以dfs统计连通块的时候要遍历所有的点。

    pta总是有一些奇怪的边缘数据,

    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1000+10;
    vector<int> G[maxn];
    int n, m, k;
    int del[maxn];
    bool vis[maxn];
    int ans[maxn];
    int no;
    
    void dfs(int u, int p){
        vis[u] = true;
        for(int i=0; i<G[u].size(); i++){
            int v = G[u][i];
            if(v == p || v==no||vis[v]) continue;
            dfs(v, u);
        }
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m>>k;
        int u, v;
        for(int i=1; i<=m; i++){
            cin>>u>>v;
            G[u].push_back(v), G[v].push_back(u);
        }
        for(int i=1; i<=k; i++){
            cin>>del[i];
            int tot = 0;
            no = del[i];
            cls(vis, 0);
            for(int j=1; j<=n; j++){
                if(j == del[i]) continue;
                if(!vis[j]){
                    tot++;
                    dfs(j, -1);
                }
            }
            ans[i] = tot-1;
        }
        for(int i=1; i<=k; i++) cout<<ans[i]<<endl;
    
    
        return 0;
    }
    

    unidirectional TSP

    记录移动状态的dp问题,还算比较的常规

    求一条路径最短的矩阵路径,若权重相同则要使行序的字典序最小。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 2000+10;
    int num[15][105];
    int dp[15][105];
    int nex[15][105];
    int n, m;
    
    int main(){
        ios::sync_with_stdio(false);
        while(~scanf("%d%d", &n, &m)){
            for(int i=1; i<=n; i++){
                for(int j=1; j<=m; j++){
                    scanf("%d", &num[i][j]);
                    dp[i][j] = inf;
                }
            }
            int ans = inf;
    
            for(int col=m; col>=1; col--){
                for(int row=1; row<=n; row++){
                    if(col == m) dp[row][col] = num[row][col];
                    else{
                        int to[3] = {row-1, row, row+1};
                        if(row == n) to[2] = 1;
                        if(row==1) to[0] = n;
                        sort(to, to+3);
                        for(int j=0; j<3; j++){
                            int temp = dp[to[j]][col+1]+num[row][col];
                            if(temp<dp[row][col]){
                                dp[row][col] = temp;
                                nex[row][col] = to[j];
                            }
                        }
                    }
                }
            }
            int mi = inf;
            int first = -1;
            for(int i=1; i<=n; i++){
                if(dp[i][1]<mi){
                    mi = dp[i][1];
                    first = i;
                }
            }
            int j=1;
            for(int i=first; j<=m; j++){
                printf("%d%c", i, j==m?'
    ':' ');
                i = nex[i][j];
            }
            printf("%d
    ", mi);
        }
    
        return 0;
    }
    
    

    The lightning system

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1000+10;
    struct Node{
        int v, k, c, l;
        bool operator < (const Node &b) const{
            return v<b.v;
        }
    }node[maxn];
    int n;
    int dp[maxn];
    int pre[maxn];
    
    
    int main(){
        ios::sync_with_stdio(false);
        while(cin>>n&&n){
    
            for(int i=1; i<=n; i++){
                cin>>node[i].v>>node[i].k>>node[i].c>>node[i].l;
                //pre[i] = pre[i-1]+node[i].l;
            }
            sort(node+1, node+1+n);
            pre[0] = 0;
            for(int i=1; i<=n; i++) dp[i] = inf, pre[i] = pre[i-1]+node[i].l;
            dp[1] = node[1].l*node[1].c+node[1].k;
            dp[0] = 0;
            for(int i=2; i<=n; i++){
                for(int j=0; j<i; j++){
                    dp[i] = min(dp[i], dp[j]+(pre[i]-pre[j])*node[i].c+node[i].k);
                }
            }
            cout<<dp[n]<<endl;
        }
    
        return 0;
    }
    
    

    jin ge jin qu(01背包)

    条件有点唬人导致不敢做背包

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 180*50+678+10;
    int dp[maxn];
    int n;
    int a[55];
    int remain;
    
    int main(){
        ios::sync_with_stdio(false);
        int _;
        cin>>_;
        int kase = 1;
        while(_--){
            cin>>n>>remain;
            int tot = 0;
            for(int i=1; i<=n; i++) cin>>a[i], tot+=a[i];
            for(int i=1; i<=remain; i++) dp[i] = -1;
            dp[0] = 0;
            for(int i=1; i<=n; i++){
                for(int v=remain-1; v>=a[i]; v--){
                    if(dp[v-a[i]]>=0){
                        dp[v] = max(dp[v], dp[v-a[i]]+1);
                    }
                }
            }
            int mx = -1;
            int last = -1;
            for(int i=remain-1; i>=0; i--){
                if(mx<dp[i]){
                    mx = dp[i];
                    last = i;
                }
            }
            cout<<"Case "<<kase++<<": "<<mx+1<<" "<<last+678<<endl;
    
    
        }
    
        return 0;
    }
    
    

    矩阵的链乘(区间dp)

    将问题转化为n-1矩阵的相乘

    时间复杂度是(O(n^3))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 100+10;
    int a[maxn];
    int dp[maxn][maxn];
    int n;
    struct Matrix{
        int x, y;
    }node[maxn];
    
    int main(){
        ios::sync_with_stdio(false);
        while(cin>>n){
            for(int i=1; i<=n; i++) cin>>a[i];
            node[1].x=a[1] ,node[1].y=a[2];
            for(int i=2; i<=n-1; i++){
                node[i].x=a[i], node[i].y=a[i+1];
            }
            cls(dp, 0x3f);
            for(int i=1; i<=n-2; i++){
                dp[i][i+1] = node[i].x*node[i].y*node[i+1].y;
            }
            for(int i=1; i<=n-1; i++) dp[i][i] = 0;
            for(int l=3; l<=n-1; l++){
                for(int i=1; i<=n-l+1; i++){
                    int j=i+l-1;
                    for(int k=i; k<=j; k++){
                        //cout<<i<<" "<<k<<" "<<j<<endl;
                        if(dp[i][k]!=inf&&dp[k+1][j]!=inf)
                            dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]+node[i].x*node[k].y*node[j].y);
                    }
                }
            }
            //cout<<dp[1][4]<<endl;
            cout<<dp[1][n-1]<<endl;
        }
    
        return 0;
    }
    
    

    uva 1626 括号完整匹配(区间dp)

    这道题的输入正的是蜜汁奇怪, 括号还可以是空串,输入间还要有空行。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1000+10;
    int dp[maxn][maxn];
    char s[105];
    
    bool match(char x, char y){
        if(x == '(' && y == ')') return true;
        if(x == '[' && y == ']') return true;
        return false;
    }
    
    void print(int l, int r){
        if(l>r) return;
        if(l == r){
            if(s[l]=='('||s[r] == ')') cout<<"()";
            else cout<<"[]";
            return ;
        }
        int ans = dp[l][r];
        if(match(s[l],  s[r])&&ans == dp[l+1][r-1]){
            cout<<s[l]; print(l+1, r-1); cout<<s[r];
            return ;
        }
        else{
            for(int i=l; i<r; i++){
                if(ans ==dp[l][i]+dp[i+1][r]){
                    print(l, i), print(i+1, r);
                    break;
                }
            }
            return ;
        }
    
    }
    
    int main(){
        ios::sync_with_stdio(false);
        int _;
        scanf("%d", &_);
        getchar();
        while(_--){
            int idx = 0;
            gets(s);
            while(s[idx] =getchar()){
                if(s[idx] == '
    ') break;
                idx++;
            }
            s[idx] = '';
            //cout<<s<<'
    ';
            int len = strlen(s);
            //cls(dp, 0x3f);
            for(int i=0; i<len; i++) {
                dp[i][i] = 1;
                dp[i+1][i] = 0;
            }
            for(int i=len-2; i>=0; i--){
                for(int j=i+1; j<len; j++){
    
                    dp[i][j] = len;
                    if(match(s[i], s[j])) dp[i][j] = min(dp[i][j], dp[i+1][j-1]);
                    for(int k=i; k<j; k++){
                        dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]);
                    }
                }
            }
            //cout<<dp[0][len-1]<<endl;
            print(0, len-1);
    
            cout<<endl;
            if(_) cout<<endl;
        }
    
        return 0;
    }
    
    

    一个任意的多边形(不一定是凸)剖分的三角形最大面积最小

    一个判断是否是凸的+区间dp

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 100+10;
    struct Node{
        int x, y;
    }node[maxn];
    int n;
    
    double dp[maxn][maxn];
    double area(Node a, Node b, Node c){
        return 1.0*abs((b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x))/2.0;
    }
    
    bool is_convex(int x, int y, int z){
        double S = area(node[z], node[x], node[y]);
        for(int i=1; i<=n; i++){
            if(i == x || i == y || i == z) continue;
            double s = area(node[i], node[x], node[y])+area(node[i], node[x], node[z])+area(node[i], node[z], node[y]);
            //点在内部,肯定非凸
            if(fabs(s-S)<1e-4) return false;
        }
        return true;
    }
    
    
    
    int main(){
        ios::sync_with_stdio(false);
        int _;
        cin>>_;
        while(_--){
            cin>>n;
            for(int i=1; i<=n; i++) cin>>node[i].x>>node[i].y;
    
            for(int l=3; l<=n; l++){
                for(int i=1; i<=n-l+1; i++){
                    int j = i+l-1;
                    if(j>n) continue;
                    dp[i][j] = 1000000000.0;
    
                    for(int k=i+1; k<j; k++){
                        if(!is_convex(i, k, j)) continue;
                        //cout<<area(node[i], node[k], node[j])<<endl;
                        dp[i][j] = min(dp[i][j], max(max(dp[i][k], dp[k][j]), area(node[i], node[k], node[j])));
                    }
                }
            }
            //cout<<dp[1][n]<<endl;
            cout<<fixed<<setprecision(1);
            cout<<dp[1][n]<<endl;
        }
        return 0;
    }
    
    

    uva1025 A spy in the metro

    一个人要在T秒的在n站见一个人,使得他在__中途等待的时间最短__, 而不是花费的总时间。

    因为终点确定了,所以要倒着dp,不然开始的状态太多了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 2000+10;
    int n, t;
    bool has_train[55][205][2];
    int dp[55][205];
    int a[maxn];
    
    int main(){
        ios::sync_with_stdio(false);
        int kase = 1;
        while(cin>>n&&n){
            cin>>t;
            for(int i=1; i<=n-1; i++) cin>>a[i];
            cls(has_train, 0);
            int m1;
            cin>>m1;
            for(int i=1; i<=m1; i++){
                int temp;
                cin>>temp;
                has_train[1][temp][0] = true;
                int tot = temp;
                for(int j=1; j<n; j++){
                    tot += a[j];
                    has_train[j+1][tot][0] = true;
                }
            }
            cin>>m1;
            for(int i=1; i<=m1; i++){
                int temp;
                cin>>temp;
                has_train[n][temp][1] = true;
                int tot = temp;
                for(int j=n-1; j>=1; j--){
                    tot += a[j];
                    has_train[j][tot][1] = true;
                }
            }
            cls(dp, 0x3f);
            //for(int i=0; i<=t-1; i++) dp[n][i] = inf;
            dp[n][t] = 0;
            for(int i=t-1; i>=0; i--){
                for(int j=1; j<=n; j++){
                    dp[j][i] = dp[j][i+1]+1;
                    if(j<n&&has_train[j][i][0]&&i+a[j]<=t){
                        dp[j][i] = min(dp[j][i], dp[j+1][i+a[j]]);
                    }
                    if(j>1&&has_train[j][i][1]&&i+a[j-1]<=t){
                        dp[j][i] = min(dp[j][i], dp[j-1][i+a[j-1]]);
                    }
                }
            }
            if(dp[1][0]<inf)
                cout<<"Case Number "<<kase++<<": "<<dp[1][0]<<"
    ";
            else cout<<"Case Number "<<kase++<<": impossible
    ";
        }
    
        return 0;
    }
    /*
    3
    3
    1 2
    1 0
    1 0
    */
    
    

    uva 437 巴比伦

    每个方块的个数没有限制,将状态进行了相应的映射,使得状态量变小。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 2000+10;
    int block[35][3];
    int dp[35][35];
    int n;
    
    void get(int* v1, int x, int y){
        int idx=0;
        bool has = false;
        for(int i=0; i<3; i++){
            if(i == y) continue;
            else v1[idx++] = block[x][i];
        }
    }
    
    int dfs(int u, int v){
        int& ans = dp[u][v];
        //cout<<u<<" "<<v<<endl;
        if(ans>0) return ans;
        int v1[2], v2[2];
        get(v1, u, v);
        for(int i=1; i<=n; i++){
            for(int j=0; j<3; j++){
                get(v2, i, j);
                //cout<<v1[0]<<" "<<v1[1]<<endl;
                //cout<<v2[0]<<" "<<v2[1]<<endl;
                if(v2[0]<v1[0]&&v2[1]<v1[1]){
                    ans = max(ans, dfs(i, j));
                }
            }
        }
        ans+=block[u][v];
        return ans;
    
    }
    
    int main(){
        ios::sync_with_stdio(false);
        int kase = 1;
        while(cin>>n&&n){
            for(int i=1; i<=n; i++){
                for(int j=0; j<3; j++) cin>>block[i][j];
                sort(block[i], block[i]+3);
            }
            int ans = 0;
            cls(dp, 0);
            for(int i=1; i<=n; i++){
                for(int j=0; j<3; j++){
                    ans = max(ans, dfs(i, j));
                }
            }
            cout<<"Case "<<kase++<<": maximum height = "<<ans<<endl;
    
    
        }
    
        return 0;
    }
    
    

    最小汉哈顿距离

    又是一个倒着更新的例子。

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1000+10;
    double dp[maxn][maxn];
    double dist[maxn][maxn];
    int x[maxn], y[maxn];
    int n;
    
    int main(){
        ios::sync_with_stdio(false);
        while(cin>>n){
            for(int i=1; i<=n; i++) cin>>x[i]>>y[i];
            for(int i=1; i<=n; i++){
                for(int j=1; j<=n; j++) {
                    dist[i][j] = sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+1.0*(y[i]-y[j])*(y[i]-y[j]));
                }
            }
            for(int i=n-1; i>=2; i--){
                //规定i>j;
                for(int j=i-1; j>=1; j--){
                    if(i == n-1) dp[i][j] = dist[n-1][n]+dist[j][n];
                    else dp[i][j] = min(dp[i+1][j]+dist[i][i+1], dp[i+1][i]+dist[j][i+1]);
                }
            }
            cout<<fixed<<setprecision(2);
            cout<<dp[2][1]+dist[1][2]<<endl;
    
        }
    
        return 0;
    }
    
    

    切割木棒

    切割n次,每一次的花费是该木棒的长度

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 50+10;
    int dp[maxn][maxn];
    int l;
    int n;
    int a[maxn];
    int dfs(int i, int j){
        if(i>=j-1) return 0;
        int &ans = dp[i][j];
        if(ans>0) return ans;
        ans = inf;
        for(int k=i+1; k<j; k++){
            ans = min(ans, dfs(i, k)+dfs(k, j));
        }
        ans += (a[j]-a[i]);
        return ans;
    }
    
    
    int main(){
        ios::sync_with_stdio(false);
        while(cin>>l&&l){
            cin>>n;
            cls(dp, 0);
            for(int i=1; i<=n; i++) cin>>a[i];
            a[0] = 0, a[n+1] = l;
            cout<<"The minimum cutting is "<<dfs(0, n+1)<<".
    ";
        }
    
        return 0;
    }
    
    

    树形dp

    uva 12186 工人的请愿书

    直属的下属在超过T%的人数之后,就会向直属上司进行报告。每一个人最少有(son[u]*T-1)/100+1;

    一种向上取整的方法

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1e5+10;
    int n, t;
    vector<int> son[maxn];
    vector<int> val[maxn];
    int dp[maxn];
    int dfs(int u){
        if(son[u].empty()) return 1;
        int &ans = dp[u];
    
        for(int i=0; i<son[u].size(); i++){
            int v = son[u][i];
            val[u].push_back(dfs(v));
        }
        //一种算下线的方法。
        int mi = (son[u].size()*t-1)/100+1;
        sort(val[u].begin(), val[u].end());
        for(int i=0; i<mi; i++) ans += val[u][i];
        return ans;
    }
    
    int main(){
        ios::sync_with_stdio(false);
        while(cin>>n>>t&&n+t){
            for(int i=0; i<=n; i++) son[i].clear(), val[i].clear();
            for(int i=0; i<=n; i++) dp[i] = 0;
            for(int i=1; i<=n; i++){
                int temp;
                cin>>temp;
                son[temp].push_back(i);
            }
            cout<<dfs(0)<<endl;
    
        }
    
        return 0;
    }
    
    

    老师教书(状压dp)

    ans>=0是已经被访问过的条件

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    #include<sstream>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 1e9;
    const int maxn = 120+10;
    int c[maxn];
    int s, m, n;
    int dp[maxn][1<<8][1<<8];
    int jiao[maxn];
    
    int dfs(int u, int s0, int s1, int s2){
        if(u == n+m+1) return s2==(1<<s)-1?0:inf;
        int &ans = dp[u][s1][s2];
        //ans>=不是>
        if(ans>=0) return ans;
        ans = inf;
        if(u>m) ans = min(ans, dfs(u+1, s0, s1, s2));
        //m0表示即将0->1人教的课。
        int m0 = (jiao[u]&s0), m1 = (jiao[u]&s1);
        //|是一种教课程的运算, ^是一种减课程的运算
        s0 = (s0^m0), s1 = (s1^m1)|(m0), s2 = (s2|m1);
        ans = min(ans, dfs(u+1, s0, s1, s2)+c[u]);
        return ans;
    
    }
    int main(){
    
        string line;
        int x;
        bool flag = false;
        while(getline(cin, line)){
            stringstream ss(line);
            ss >> s >> m >> n;
            if(s == 0) break;
            for(int i = 1; i <= m+n; i++) {
              getline(cin, line);
              stringstream ss(line);
              ss >> c[i];
              jiao[i] = 0;
              while(ss >> x) jiao[i] |= (1<<(x-1));
            }
            //memset(dp, -1, sizeof(dp));
            cls(dp, -1);
            cout << dfs(1, (1<<s)-1, 0, 0) << "
    ";
    
        }
    
        return 0;
    }
    
    

    uva 1252 (状压dp)

    最多11个特征,n个物品,问最多问多少次能一定确定一个物品。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 128+5;;
    const int maxm = 11;
    int d[1<<maxm][1<<maxm];
    string feature[maxn];
    bool vis[1<<maxm][1<<maxm];
    int m, n;
    int cnt[1<<maxm][1<<maxm];
    
    
    int dp(int s, int a){
        if(cnt[s][a]<=1) return 0;
        if(cnt[s][a] == 2) return 1;
        int &ans = d[s][a];
        if(vis[s][a]) return ans;
        vis[s][a] = true;
        ans = inf;
    
        for(int i=0; i<m; i++){
            if(!(s&(1<<i))){
                int s1 = s^(1<<i), a1 = a^(1<<i);
                //增加一个i特征的询问
                d[s][a] = min(d[s][a], (max(dp(s1, a1), dp(s1, a))+1));
            }
        }
        return ans;
    }
    
    void init(){
        for(int s=0; s<(1<<m); s++){
            for(int a=s; a; a=(a-1)&s){
                cnt[s][a] = 0;
            }
            cnt[s][0] = 0;
        }
        for(int i=0; i<n; i++){
            int tot = 0;
            for(int j=0; j<m; j++){
                if(feature[i][j] == '1'){
                    tot += (1<<j);
                }
            }
            for(int s=0; s<(1<<m); s++){
                cnt[s][s&tot]++;
            }
        }
    }
    
    
    int main(){
        ios::sync_with_stdio(false);
        int kase = 1;
        while(cin>>m>>n&&n+m){
            for(int i=0; i<n; i++) cin>>feature[i];
            init();
            cls(vis, 0);
            cout<<dp(0, 0)<<"
    ";
            kase++;
        }
    
        return 0;
    }
    
    

    LCS 转化为LIS

    两个序列中,每一个序列里面的数字都只出现了一次,因此可以来转化

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 250*250+10;
    int a[maxn], b[maxn];
    int c[maxn];
    int n, p, q;
    map<int, int> mp;
    int g[maxn];
    int d[maxn];
    int main(){
        ios::sync_with_stdio(false);
        int kase = 1;
        int _;
        cin>>_;
        while(_--){
            cin>>n>>p>>q;
            mp.clear();
            for(int i=1; i<=p+1; i++) cin>>a[i], mp[a[i]] = i;
            for(int i=1; i<=q+1; i++) cin>>b[i];
            int idx = 1;
            for(int i=1; i<=q+1; i++) if(mp[b[i]])c[idx++] = mp[b[i]];
    
    //        for(int i=1; i<=q; i++) cout<<b[i]<<" ";
    //        cout<<endl;
            int ans = 0;
            cls(g, 0x3f);
            for(int i=1; i<idx; i++){
                int k=lower_bound(g+1, g+idx, c[i])-g;
    
                d[i] = k;
                g[k] = c[i];
                ans = max(ans, d[i]);
            }
            cout<<"Case "<<kase++<<": "<<ans<<endl;
        }
    
        return 0;
    }
    /*
    1
    10 7 8
    1 7 5 4 8 3 9
    1 4 3 5 6 2 8 9
    */
    
    

    约瑟夫环

    [f[i] = (f[i-1]+k)\%i ]

    由于是从m号开始的,(f[n] = (m-k+1+f[n])\%n), 最后判断f[n]<=0是否成立,否则+n.

    初始化(f[1] = 0)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1e4+10;
    int d[maxn];
    int n, k, m;
    
    int main(){
        ios::sync_with_stdio(false);
        while(cin>>n>>k>>m&&n+k+m){
            d[1] = 0;
            for(int i=2; i<=n; i++){
                d[i] = (d[i-1]+k)%i;
            }
            d[n] = (m-k+1+d[n])%n;
            if(d[n]<=0) d[n]+=n;
            cout<<d[n]<<endl;
        }
    
        return 0;
    }
    
    

    博弈+dp

    (dp[i][j]表示(i, j)区间先手的取的最大值)

    时间复杂度是(O(n^2))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 200+10;
    int a[maxn];
    int dp[maxn][maxn];
    int z[maxn][maxn], y[maxn][maxn];
    int n;
    int pre[maxn];
    
    
    int main(){
        ios::sync_with_stdio(false);
        while(cin>>n&&n){
            for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) dp[i][j] = -inf;
            for(int i=1; i<=n; i++){
                cin>>a[i];
                pre[i] = pre[i-1]+a[i];
            }
            for(int i=1; i<=n; i++) dp[i][i] = z[i][i] = y[i][i] = a[i];
    
            for(int l=1; l<=n; l++){
                for(int i=1; i<=n-l; i++){
                    int j=i+l;
                    int mi = 0;
                    mi = min(mi, y[i][j-1]);
                    mi = min(mi, z[i+1][j]);
                    dp[i][j] = max(dp[i][j], pre[j]-pre[i-1]-mi);
                    y[i][j] = min(y[i][j-1], dp[i][j]);
                    z[i][j] = min(z[i+1][j], dp[i][j]);
                }
            }
            cout<<2*dp[1][n]-pre[n]<<endl;
        }
    
        return 0;
    }
    
    

    停掉最多的服务(状压dp)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 17;
    int cover[1<<maxn];
    int d[1<<maxn];
    int graph[maxn];
    int n;
    
    
    
    int main(){
        ios::sync_with_stdio(false);
        int kase = 1;
        while(cin>>n&&n){
            int m;
            cls(graph, 0);
            cls(cover, 0);
            for(int i=0; i<n; i++){
                cin>>m;
                int v;
                graph[i] = (1<<i);
                for(int j=0; j<m; j++) {
                    cin>>v;
                    graph[i] |= (1<<v);
                }
            }
            for(int s=1; s<(1<<n); s++){
    
                for(int i=0; i<n; i++){
                    if(s&(1<<i)){
                        cover[s] |= graph[i];
                    }
                }
            }
    
            cls(d, 0);
            d[0] = 0;
            for(int s=1; s<(1<<n); s++){
    
                for(int s0=s; s0; s0=(s0-1)&s){
                    if(cover[s0] == (1<<n)-1){
                        //s0已经可以停掉一个服务了,剩下接着找。
                        d[s] = max(d[s^s0]+1, d[s]);
                    }
                }
            }
    
            cout<<"Case "<<kase++<<": "<<d[(1<<n)-1]<<endl;
    
        }
    
        return 0;
    }
    
    

    森林的最小点覆盖+最多的一条边被两点覆盖

    树形dp

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1000+10;
    const int M = 2000;
    vector<int> G[maxn];
    int n, m;
    
    bool vis[maxn][2];
    int d[maxn][2];
    
    
    
    int dp(int u, int state, int p){
        if(vis[u][state]) return d[u][state];
        vis[u][state] = true;
        int &ans = d[u][state];
        //点亮该灯
        ans=M;
        for(int i=0; i<G[u].size(); i++){
            int v = G[u][i];
            if(p!=v){
                ans += dp(v, 1, u);
    
            }
        }
        if(state == 0&&p>=0) ans++;
    
    
        //不点该灯
        if(p<0||state == 1){
            int ans1=0;
            for(int i=0; i<G[u].size(); i++){
                int v = G[u][i];
                if(p!=v){
                    ans1 += dp(v, 0, u);
                }
            }
            if(p>=0) ans1++;
            ans = min(ans, ans1);
        }
    
    
        //若父亲没点,这条边仅一次被点亮
    
        return ans;
    
    }
    
    
    
    int main(){
        ios::sync_with_stdio(false);
        int _;
        cin>>_;
        while(_--){
            cin>>n>>m;
            int u, v;
            for(int i=0; i<n; i++) G[i].clear(), d[i][0] = d[i][1] = 0, vis[i][0] = vis[i][1] = false;
            for(int i=1;i<=m; i++){
                cin>>u>>v;
                G[u].push_back(v), G[v].push_back(u);
            }
            int ans = 0;
            for(int i=0; i<n; i++){
                if(!vis[i][0]){
                    ans += dp(i, 0, -1);
                }
            }
            cout<<ans/2000<<" "<<m-(ans%2000)<<" "<<ans%2000<<endl;
        }
    
        return 0;
    }
    
    

    带有滑动窗口的线性dp

    按序取垃圾,使得最后的经过的距离最短。

    注意条件:垃圾重量是单调增的,所以可以使用滑动窗口。

    uva的PE居然显示的是WA。。。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 1e5+10;
    int C;
    struct Node{
        int x, y, weight;
    }node[maxn];
    int pre_dist[maxn];
    int pre_weight[maxn];
    int pre[maxn];
    int n;
    int d[maxn];
    int q[maxn];
    
    int get(int j){
        return d[j]+abs(node[j+1].x)+abs(node[j+1].y)-pre[j+1];
    }
    
    
    int main(){
        ios::sync_with_stdio(false);
        int _;
        cin>>_;
        while(_--){
            cin>>C;
            cin>>n;
            int x, y, w;
            pre[0] = 0;
            pre_weight[0] = pre_dist[0] = 0;
            for(int i=1; i<=n; i++){
                cin>>x>>y>>w;
                node[i] = Node{x, y, w};
                pre_weight[i] = pre_weight[i-1]+w;
                pre[i] = pre[i-1]+abs(x-node[i-1].x)+abs(y-node[i-1].y);
            }
            int l, r;
            l=r=1;
            q[l] = 0;
            cls(d, 0x3f);
            d[0] = 0;
            for(int i=1; i<=n; i++){
                while(l<=r&&pre_weight[i]-pre_weight[q[l]]>C)l++;
                d[i] = min(d[i], get(q[l]));
                d[i] += (pre[i]+abs(node[i].x)+abs(node[i].y));
                //cout<<i<<" "<<d[i]<<endl;
                while(l<=r&&get(q[r])>=get(i))r--;
                q[++r] = i;
            }
            cout<<d[n]<<endl;
            if(_>0) cout<<endl; 
    
        }
    
        return 0;
    }
    
    

    内否切割成目标的矩形块(状压dp)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 15;
    int n, x, y;
    int a[maxn];
    int d[1<<maxn][105];
    bool vis[1<<maxn][105];
    int s[1<<maxn];
    
    int cou(int x){
        return x==0?0:cou(x/2)+(x&1);
    }
    
    int dp(int S, int x){
        if(vis[S][x]) return d[S][x];
        vis[S][x] = true;
        int &ans = d[S][x];
        if(cou(S) == 1) return ans = 1;
        int y = s[S]/x;
        for(int s1=(S-1)&S; s1; s1=(s1-1)&S){
            int s2 = S-s1;
            //沿y切
            if(s[s1]%x == 0&&dp(s1, min(x, s[s1]/x))&&dp(s2, min(x, s[s2]/x))) return ans=1;
            if(s[s1]%y == 0&&dp(s1, min(y, s[s1]/y))&&dp(s2, min(y, s[s2]/y))) return ans=1;
        }
        return ans=0;
    }
    
    
    int main(){
        ios::sync_with_stdio(false);
        int kase = 1;
        while(cin>>n){
            if(!n) break;
            cls(vis, 0);
            cin>>x>>y;
            for(int i=0; i<n; i++) cin>>a[i];
            cls(s, 0);
            for(int i=0; i<(1<<n); i++){
                for(int j=0; j<n; j++) if(i&(1<<j)) s[i] += a[j];
            }
            int ans = 0;
            //cout<<s[(1<<n)-1]<<endl;
            if(s[(1<<n)-1]!=x*y||s[(1<<n)-1]%x) ans = 0;
            else ans = dp((1<<n)-1, min(x, y));
            if(ans){
                cout<<"Case "<<kase++<<": Yes"<<endl;
            }
            else{
                cout<<"Case "<<kase++<<": No"<<endl;
            }
    
        }
    
        return 0;
    }
    
    

    分割团队(正负背包)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 100+10;
    bool vis[maxn];
    int G[maxn][maxn];
    int color[maxn];
    vector<int> team[maxn][2];
    int no;
    int d[maxn][maxn<<1];
    int diff[maxn];
    int n;
    
    bool dfs(int x, int col){
        color[x] = col;
        //cout<<x<<" "<<col<<endl;
        team[no][col-1].push_back(x);
        for(int i=1; i<=n; i++){
            if(i == x) continue;
            if(!(G[i][x]&&G[x][i])){
                if(color[i] == col) return false;
                if(!color[i]&&!dfs(i, 3-col)) return false;
            }
        }
        return true;
    }
    
    bool build(){
        cls(color, 0);
        no = 0;
        for(int i=1; i<=n; i++){
            if(!color[i]){
                team[no][0].clear(), team[no][1].clear();
                if(!dfs(i, 1)) return false;
                diff[no] = team[no][0].size()-team[no][1].size();
                no++;
            }
        }
        return true;
    
    }
    
    void prin(int ans){
        vector<int> team1, team2;
        for(int i=no-1; i>=0; i--){
            int t;
            //cout<<i<<" "<<ans<<endl;
            if(d[i][ans+n-diff[i]]){
                t=0;
                ans -= diff[i];
            }
            else{
                t =1;
                ans += diff[i];
            }
            //cout<<ans<<endl;
            for(int j=0; j<team[i][t].size(); j++){
                team1.push_back(team[i][t][j]);
            }
            for(int j=0; j<team[i][t^1].size(); j++){
                team2.push_back(team[i][t^1][j]);
            }
        }
        cout<<team1.size();
        for(int i=0; i<team1.size(); i++) cout<<" "<<team1[i];
        cout<<endl;
        cout<<team2.size();
        for(int i=0; i<team2.size(); i++) cout<<" "<<team2[i];
        cout<<endl;
    }
    
    void dp(){
        cls(d, 0);
        d[0][0+n] = 1;
        for(int i=0; i<no; i++){
            for(int j=-n; j<=n; j++) if(d[i][j+n]){
                d[i+1][j+n+diff[i]] = 1;
                d[i+1][j+n-diff[i]] = 1;
            }
        }
        for(int ans = 0; ans<=n; ans++){
            if(d[no][ans+n]) {prin(ans); return;}
            if(d[no][-ans+n]) {prin(-ans); return;}
        }
    
    }
    
    int main(){
        ios::sync_with_stdio(false);
        int _;
        cin>>_;
        while(_--){
            cin>>n;
            cls(G, 0);
            for(int i=1; i<=n; i++){
                int id;
    
                while(cin>>id&&id){
                    G[i][id] = 1;
                }
    
            }
            if(n==1||!build()) cout<<"No solution
    ";
        else{
    
                dp();
            }
            if(_) cout<<"
    ";
    
        }
    
        return 0;
    }
    /*
    2
    5
    3 4 5 0
    1 3 5 0
    2 1 4 5 0
    2 3 5 0
    1 2 3 4 0
    
    5
    2 3 5 0
    1 4 5 3 0
    1 2 5 0
    1 2 3 0
    4 3 2 1 0
    */
    
    

    兑换货币(正负背包)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<bitset>
    #include <unordered_map>
    #include <unordered_set>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    #define pb(x) push_back(x)
    #define cls(x, val) memset(x, val, sizeof(x))
    #define fi first
    #define se second
    #define mp(x, y) make_pair(x, y)
    #define inc(i, l, r) for(int i=l; i<=r; i++)
    const int inf = 0x3f3f3f3f;
    const int maxn = 2000+10;
    int num[10];
    int dp[maxn];
    int main(){
        ios::sync_with_stdio(false);
        int _;
        scanf("%d", &_);
        while(_--){
            for(int i=1; i<=6; i++) scanf("%d", &num[i]);
            for(int i=1; i<=2000; i++) dp[i] = inf;
            dp[0] = 0;
            for(int i=1; i<=6; i++){
                for(int j=num[i]; j<=2000; j++){
                    dp[j] = min(dp[j], dp[j-num[i]]+1);
                }
            }
            for(int i=1; i<=6; i++){
                for(int j=2000-num[i]; j>=0; j--){
                    dp[j] = min(dp[j], dp[j+num[i]]+1);
                }
            }
            int ans = 0;
            
            int mx = -1;
            for(int i=1;i<=100; i++){
                mx = max(mx, dp[i]);
                ans += dp[i];
            }
            printf("%.2lf %d
    ", double(ans)/100.0, mx);
        }
        return 0;
    }
    
  • 相关阅读:
    java se 转到ee小结
    objective c基本知识
    2013_11_14:递归算法(2)—全排列
    2013_11_13:递归算法(1)
    2013_11_13:关于 new 和delelte 的使用
    c++调试问题
    模式匹配BM算法介绍与实现
    一个n数组求和问题
    机试题
    算法题目
  • 原文地址:https://www.cnblogs.com/babydragon/p/11444201.html
Copyright © 2020-2023  润新知