计蒜客2015 初赛题解及代码

2015 计蒜客初赛题解之工作区的颜值选择

标签(空格分隔): ACM

题解思路

  • 简单数据 暴力代码
#include <iostream>
#include <cstdio>
using namespace std;
const int Maxn = 2, Maxm = 3;
int C[Maxn][Maxm], U[Maxn][Maxm], W[Maxn][Maxm];
int n, m, k;
inline int abs(int x) {
    return x < 0 ? -x : x;
}
inline int cost(int c, int i, int j) {
    return (abs(c + i + j + 2) ^ U[i][j]) * W[i][j];
}
int dirx[] = {-1, 0, 1, 0};
int diry[] = {0, -1, 0, 1};
int optimize(int x, int y) {
    if (y >= m) return 0;
    if (x >= n) return optimize(x ^ 1, y + 1);
    int best = -1;
    for (int i = -k; i <= k; ++i) {
        int tmp = cost(i,x, y);
        for (int l = 0; l < 4; ++l) {
            int nx = dirx[l] + x;
            int ny = diry[l] + y;
            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            tmp += abs(i + C[nx][ny]);
        }
        if (best == -1 || tmp < best) best = tmp;
    }
    return best + optimize(x ^ 1, y + 1);
}
int solve(int x, int y) {
    if (y >= m) return optimize(1, 0);
    if (x >= n) return solve(x ^ 1, y + 1);
    int ans = -1;
    for (int i = -k; i <= k; ++i) {
        C[x][y] = i;
        if (ans == -1) ans = solve(x ^ 1, y + 1) + cost(i, x, y);
        else ans = min(ans, solve(x ^ 1, y + 1) + cost(i, x, y));
    }
    return ans;
}
int main(){
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &U[i][j]);
        }
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &W[i][j]);
        }
    }
    printf("%d\n", solve(0, 0));
    return 0;
}
  • 中等数据 动态规划代码(题目范围出错 n可以等于1)
#include <iostream>
#include <cstdio>
using namespace std;
const int Maxn = 2, Maxm = 33, Maxk=33, INF = 0x7FFFFFFF;
int U[Maxn][Maxm], W[Maxn][Maxm];
int n, m, k;
inline int abs(int x) {
    return x < 0 ? -x : x;
}
inline int cost(int c, int i, int j) {
    return (abs(c + i + j + 2) ^ U[i][j]) * W[i][j];
}
inline int ID(int x) {
    return x + Maxk;
}
int dp[Maxm][Maxk << 1][Maxk << 1];
int neg_decision[Maxm][Maxk << 1][Maxk << 1];
int pos_decision[Maxm][Maxk << 1][Maxk << 1];

int solve() {
    for (int i = -k; i <= k; ++i) {
        for (int j = -k; j <= k; ++j) {
            dp[0][ID(i)][ID(j)] = cost(i, 0, 0) + cost(j, 1, 0) + abs(i + j);
        }

        int neg = -k;
        int pos = k;
        for (int j = -k; j <= k; ++j) {
            if (dp[0][ID(i)][ID(j)] - j < dp[0][ID(i)][ID(neg)] - neg)
                neg_decision[0][ID(i)][ID(j)] = j;
            else neg_decision[0][ID(i)][ID(j)] = neg;

            if (dp[0][ID(i)][ID(-j)] - j < dp[0][ID(i)][ID(pos)] + pos)
                pos_decision[0][ID(i)][ID(-j)] = -j;
            else pos_decision[0][ID(i)][ID(-j)] = pos;

            neg = neg_decision[0][ID(i)][ID(j)];
            pos = pos_decision[0][ID(i)][ID(-j)];
        }
    }

    for (int t = 1; t < m; ++t) {
        for (int i = -k; i <= k; ++i) {
            for (int j = -k; j <= k; ++j){
                int& tmp = dp[t][ID(i)][ID(j)]; 
                tmp = INF;
                for (int l = -k; l <= k; ++l) {
                    int _neg = neg_decision[t - 1][ID(l)][ID(-j)];
                    int _pos = pos_decision[t - 1][ID(l)][ID(-j)];
                    tmp = min(dp[t - 1][ID(l)][ID(_neg)] - _neg - j  + abs(l + i), tmp);
                    tmp = min(dp[t - 1][ID(l)][ID(_pos)] + _pos + j  + abs(l + i), tmp);
                }
                tmp += abs(i + j) + cost(i, 0, t) + cost(j, 1, t);
            }
            int neg = -k;
            int pos = k;
            for (int j = -k; j <= k; ++j){
                if (dp[t][ID(i)][ID(j)] - j < dp[t][ID(i)][ID(neg)] - neg)
                    neg_decision[t][ID(i)][ID(j)] = j;
                else neg_decision[t][ID(i)][ID(j)] = neg;
                if (dp[t][ID(i)][ID(-j)] - j < dp[t][ID(i)][ID(pos)] + pos)
                    pos_decision[t][ID(i)][ID(-j)] = -j;
                else pos_decision[t][ID(i)][ID(-j)] = pos;

                neg = neg_decision[t][ID(i)][ID(j)];
                pos = pos_decision[t][ID(i)][ID(-j)];
            }
        }
    }
    int ans = INF;
    for (int i = -k; i <= k; ++i)
        for (int j = -k; j <= k; ++j)
            ans = min(ans, dp[m - 1][ID(i)][ID(j)]);
    return ans;
}
int dp1[Maxm][Maxk << 1];
int solve_n_1() {
    for (int i = -k; i <= k; ++i)
        dp1[0][ID(i)] = cost(i, 0, 0);
    for (int t = 1; t < m; ++t) {
        for (int i = -k; i <= k; ++i) {
            dp1[t][ID(i)] = INF;
            for (int j = -k; j <= k; ++j) {
                dp1[t][ID(i)] = min(dp1[t][ID(i)], dp1[t - 1][ID(j)] + abs(i + j) + cost(i, 0, t));
            }
        }
    }
    int ans = INF;
    for (int i = -k; i <= k; ++i)
        ans = min(ans, dp1[m - 1][ID(i)]);
    return ans;
}
int main(){
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &U[i][j]);
        }
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &W[i][j]);
        }
    }
    if (n == 1) printf("%d\n", solve_n_1());
    else printf("%d\n", solve());
    return 0;
}
  • 困难数据 网络流代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 100000, INF = (1 << 30) - 1;
const int Maxn = 33, Maxm = 33, Maxk=33;
int U[Maxn][Maxm], W[Maxn][Maxm];
int n, m, k;
inline int abs(int x) {
    return x < 0 ? -x : x;
}
inline int cost(int c, int i, int j) {
    return (abs(c + i + j + 2) ^ U[i][j]) * W[i][j];
}
struct Edge {
    int to, f, next;
    Edge(){}
    Edge(int to, int f, int next): to(to), f(f), next(next){}
}edge[MAXN * 4];
int box[MAXN], size;
void add(int from, int to, int f){
    edge[size] = Edge(to, f, box[from]);
    box[from] = size++;
}

int deep[MAXN],depnum[MAXN];// depnum记录各个距离的个数
bool isEnd;
int s,t,N;
void bfs()//反向分层
{
    memset(deep,-1,sizeof(deep));
    memset(depnum,0,sizeof(depnum));
    deep[t]=0;
    depnum[0]++;
    int que[MAXN],in=0,out=0;
    que[in++]=t;
    while(in>out)
    {
        int x=que[out++];
        for(int i=box[x];i!=-1;i=edge[i].next)
        {
            int x1=edge[i].to;
            if(edge[i^1].f==0||deep[x1]!=-1)continue;
            que[in++]=x1;
            deep[x1]=deep[x]+1;
            depnum[deep[x1]]++;
        }
    }
    if(deep[s]==-1) isEnd=true;
    else isEnd=false;
}
int dfs(int x,int flow)
{
    if(x==t)return flow; 
    if(isEnd||flow==0)return 0;
    int tmp=0;
    int min1=deep[x]+1;
    for(int i=box[x];i!=-1;i=edge[i].next)
    {
        int x1=edge[i].to;      if(edge[i].f==0||deep[x1]==N||deep[x1]==-1)continue;
        if(deep[x1]==deep[x]-1)//如果有有效路径则更新下一结点
        {
            int tmp1=dfs(x1,min(edge[i].f,flow-tmp));
            edge[i].f-=tmp1;
            edge[i^1].f+=tmp1;
        tmp+=tmp1;  
        }
        if(edge[i].f)min1=min(min1,deep[x1]+1);
    }  
    depnum[min1]++;
    depnum[deep[x]]--;
    if(depnum[deep[x]]==0)isEnd=true;
    deep[x]=min1;
    return tmp;
}
int sap()
{
    //N=n+2;
    //s=n,t=n+1;
    int ans=0;
    bfs();
    while(deep[s]<N&&!isEnd)
    {
        ans+=dfs(s,INF);
    }
    return ans;
}

int solve() {
    memset(box, -1, sizeof(box)); size = 0;
    s = 0;
    t = (2 * k + 2) * n * m + 1;
    int id = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            int first = id * (2 * k + 2) + 1;
            int last = first + 2 * k + 1;
            for (int l = first; l < last; ++l) {
                add(l, l + 1, cost(-k + l - first, i, j));
                add(l + 1, l, cost(-k + l - first, i, j));
            }
            if ((i + j) & 1) swap(first, last);
            add(s, first, INF);
            add(first, s, 0);
            add(last, t, INF);
            add(t, last, 0);  
            id++;
        }
    }

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            int cur = (i * m + j) * (2 * k + 2) + 1;
            if (j) {
                int left = (i * m + j - 1) * (2 * k + 2) + 1;
                for (int l = 0; l < 2 * k + 2; ++l) {
                    add (left + 2 * k + 1 - l, cur + l, 1);
                    add (cur + l, left + 2 * k + 1 - l, 1);
                }

            }
            if (i) {
                int up = ((i - 1) * m + j) * (2 * k + 2) + 1;
                for (int l = 0; l < 2 * k + 2; ++l) {
                    add (up + 2 * k + 1 - l, cur + l, 1);
                    add (cur + l, up + 2 * k + 1 - l, 1);
                }
            }
        }
    }
    N = t + 1;

    return sap();
}

int main(){
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &U[i][j]);
        }
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &W[i][j]);
        }
    }
    printf("%d\n", solve());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值