首页 > 代码库 > Zepto Code Rush 2014——Dungeons and Candies

Zepto Code Rush 2014——Dungeons and Candies

题目链接

  • 题意:
    k个点,每个点都是一个n * m的char型矩阵。对与每个点,权值为n * m或者找到一个之前的点,取两个矩阵对应位置不同的字符个数乘以w。找到一个序列,使得所有点的权值和最小
  • 分析:
    首先,这个图是一个无向图。求权值和最小,每个权值对应的是一条边,且每个点只能有一个权值即一条边,一个k个边,和生成树很像,但是需要证明不能有环形。不妨假设现在有三个点,每个点的最小边成环,这时候是不能找到一个序列使得每个点都取到它的最小边值的,所以,k个点k个边不能有环且边值和最小,就是最小生成树。


prim算法:
const int maxn = 1100;

char ipt[maxn][11][11];
int dist[maxn][maxn];
int d[maxn], p[maxn];
bool vis[maxn];
int n, m, k, w;

int main()
{
//    freopen("in.txt", "r", stdin);
    while (~RIV(n, m, k, w))
    {
        CLR(dist, 0);
        REP(i, k)
        {
            vis[i] = false;
            d[i] = n * m;
            p[i] = -1;
        }

        REP(i, k) REP(j, n)
            RS(ipt[i][j]);
        REP(i, k) REP(j, k) REP(ii, n) REP(jj, m)
            dist[i][j] += (ipt[i][ii][jj] != ipt[j][ii][jj]) * w;
        d[0] = 0;
        int sum = n * m;
        VI ans;
        REP(i, k)
        {
            int M = INF, ind;
            REP(j, k)
                if (!vis[j] && d[j] < M)
                {
                    ind = j;
                    M = d[j];
                }
            vis[ind] = true;
            sum += M;
            ans.push_back(ind);
            REP(j, k)
            {
                if (!vis[j] && dist[ind][j] < d[j])
                {
                    d[j] = dist[ind][j];
                    p[j] = ind;
                }
            }
        }
        WI(sum);
        REP(i, ans.size())
        {
            cout << ans[i] + 1 << ' ' << p[ans[i]] + 1 << endl;
        }
    }
    return 0;
}


kruskal:
const int maxn = 1100;

struct Edge
{
    int from, to, dist;
    int operator< (const Edge& rhs) const
    {
        return dist < rhs.dist;
    }
    Edge (int from = 0, int to = 0, int dist = 0)
    {
        this->from = from;
        this->to = to;
        this->dist = dist;
    }
};

vector<Edge> G[maxn];
int in[maxn];
vector<Edge> edges;
int fa[maxn];
char ipt[maxn][105];
int diff[maxn][maxn];
int n, m, k, w;
int find(int n)
{
    return (n == fa[n]) ? n : (fa[n] = find(fa[n]));
}
void init(int n)
{
    REP(i, n)
    {
        fa[i] = i;
        G[i].clear();
        in[i] = 0;
    }
    edges.clear();
}
void AddEdge(int u, int v, int dist)
{
    edges.push_back(Edge(u, v, dist));
}
void dfs(int u, int fa)
{
    REP(i, G[u].size())
    {
        Edge& e = G[u][i];
        if (e.to != fa)
        {
            if (e.dist == m * n)
                cout << e.to + 1 << ' ' << 0 << endl;
            else
                cout << e.to + 1 << ' ' << u + 1 << endl;
            dfs(e.to, u);
        }
    }
}
void solve()
{
    int ret = 0;
    sort(all(edges));
    REP(i, edges.size())
    {
        Edge& e = edges[i];
        int ru = find(e.from), rv = find(e.to);
        if (ru != rv)
        {
            fa[ru] = rv;
            ret += e.dist;
            G[e.from].push_back(Edge(e.from, e.to, e.dist));
            G[e.to].push_back(Edge(e.to, e.from, e.dist));
            in[e.from]++;
            in[e.to]++;
        }
    }
    WI(ret + n * m);
    REP(i, k)
    {
        if (in[i] <= 1)
        {
            cout << i + 1 << ' ' << 0 << endl;
            dfs(i, -1);
            break;
        }
    }
}

int judge(int a, int b)
{
    int cnt = 0;
    REP(i, n * m)
        cnt += (ipt[a][i] != ipt[b][i]);
    return cnt;
}

int main()
{
//    freopen("in.txt", "r", stdin);
    while (~RIV(n, m, k, w))
    {
        CLR(diff, 0);
        REP(i, k)
        {
            int len = 0;
            REP(j, n)
            {
                RS(ipt[i] + len);
                len = strlen(ipt[i]);
            }
        }
        REP(i, k) REP(j, k) REP(t, n * m)
            diff[i][j] += (ipt[i][t] != ipt[j][t]);
        init(k);
        REP(i, k) REP(j, k)
        {
            if (i == j)
                continue;
            AddEdge(i, j, min(diff[i][j] * w, n * m));
        }
        solve();
    }
    return 0;
}