BZOJ1001

这道题目的题解在网上还是比较多的。首先先在这里整理一些平面图性质:

1) 平面图最小割等于对偶图s-t的最短路

2)平面图的生成树个数等于对偶图生成树的个数(不过好像1002的对偶图的Kirchoff矩阵=原图Kirchoff矩阵?)

反正这一题第一条就足够了。

那么怎么确定s和t在哪里?s就是填上s和t的边后产生的附加面,而t就是无界面。

想到这样,就开始写了。不过添加边的过程比较复杂,最好手推一下公式。为了方便,我设计了一个CShortestSolver的类。这样就很清晰了。

不多说,上代码:

#include <iostream>
#include <queue>
#include <cstdlib>
#include <cstring>

using namespace std;

const int maxm = 2500000;
//max node
const int maxn = 7000000;
//max size

struct edge
{
    int to;
    int next;
    int w;
};

struct node
{
    int d;
    int id;
    friend bool operator<(node a,node b)
    {
        return (a.d>b.d);
    }
};

class CShortestSolver
{
private:
    int head[maxm];
    edge e[maxn];
    int cur;
    priority_queue<node> q;
    bool vis[maxm];
private:
    void init(int source,int size);
public:
    CShortestSolver();
    void addEdge(int from,int to,int weight);
    int solve(int source,int size,int des);
};

CShortestSolver solver;

CShortestSolver::CShortestSolver()
{
    memset(head,-1,sizeof head);
    cur = 0;
};

void CShortestSolver::addEdge(int from,int to,int weight)
{
    //cout << "Zulagen fra" << from << "fo" << to << endl;
    e[cur].next = head[from];
    e[cur].to = to;
    e[cur].w = weight;
    head[from] = cur;
    cur++;
};

void CShortestSolver::init(int source,int size)
{
    memset(vis,false,sizeof(vis));
    node temp;
    for (int i = 1;i <= size;++i)
    {
        if (i != source)
        {
            temp.d = 2147483647;
            temp.id = i;
            q.push(temp);
        }
        else
        {
            temp.d = 0;
            temp.id = i;
            q.push(temp);
        }
    }
}

int CShortestSolver::solve(int source,int size,int des)
{
    init(source,size);
    node temp;
    int cnt = 1;
    while (cnt <= size)
    {
        node top = q.top();
        q.pop();
        if (vis[top.id]) continue;
        cnt++;
        if (top.id == des) return top.d;
        vis[top.id] = true;
        int cur = head[top.id];
        while (cur != -1)
        {
            temp.id = e[cur].to;
            temp.d = top.d + e[cur].w;
            q.push(temp);
            cur = e[cur].next;
        }
    }
    return -1;
}

int main(int argc,char * argv[])
{
    int n,m;
    cin >> n >> m;
    for (int i = 1;i <= n;++i)
    {
        for (int j = 1;j <= m-1;++j)
        {
            int w;
            cin >> w;
            if (i == 1)
            {
                solver.addEdge(2*j,2*(n-1)*(m-1)+1,w);
                solver.addEdge(2*(n-1)*(m-1)+1,2*j,w);
            }
            else if (i == n)
            {
                solver.addEdge(2*(n-2)*(m-1)+2*(j-1)+1,2*(n-1)*(m-1)+2,w);
                solver.addEdge(2*(n-1)*(m-1)+2,2*(n-2)*(m-1)+2*(j-1)+1,w);
                
            }
            else
            {
                solver.addEdge(2*(m-1)*(i-2)+2*(j-1)+1,2*(m-1)*(i-1)+2*(j-1)+2,w);
                solver.addEdge(2*(m-1)*(i-1)+2*(j-1)+2,2*(m-1)*(i-2)+2*(j-1)+1,w);
            }
        }
    }
    for (int i = 1;i <= n-1;++i)
    {
        for (int j = 1;j <= m;++j)
        {
            int w;
            cin >> w;
            if (j == 1)
            {
                solver.addEdge(2*(n-1)*(m-1)+2,2*(m-1)*(i-1)+1,w);
                solver.addEdge(2*(m-1)*(i-1)+1,2*(n-1)*(m-1)+2,w);
            }
            else if (j == m)
            {
                solver.addEdge(2*(m-1)*(i-1)+2*j-2,2*(n-1)*(m-1)+1,w);
                solver.addEdge(2*(n-1)*(m-1)+1,2*(m-1)*(i-1)+2*j-2,w);
            }
            else
            {
                solver.addEdge(2*(m-1)*(i-1)+2*(j-1),2*(m-1)*(i-1)+2*j-1,w);
                solver.addEdge(2*(m-1)*(i-1)+2*j-1,2*(m-1)*(i-1)+2*j-2,w);
            }
        }
        
    }
    for (int i = 1;i <= n-1;++i)
    {
        for (int j = 1;j <= m-1;++j)
        {
            int w;
            cin >> w;
            solver.addEdge(2*(m-1)*(i-1)+2*(j-1)+1,2*(m-1)*(i-1)+2*(j-1)+2,w);
            solver.addEdge(2*(m-1)*(i-1)+2*(j-1)+2,2*(m-1)*(i-1)+2*(j-1)+1,w);
        }
    }
    int ans = solver.solve(2*(n-1)*(m-1)+1,2*(n-1)*(m-1)+2,2*(n-1)*(m-1)+2);
    cout << ans << endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值