BZOJ1003

这里说一说心得。当你看到一道题目的时候,如果这条思路走不通,那么快点换一个思路。

当时我一直在想如何用构图体现换路线,但是发现走不通。其实,如果采用区间DP,就能显示”换路线“的意思了。

还有,题目中如果给出的是m,n最好换成你看得懂的词语,不然容易打乱。

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

using namespace std;

const int maxm = 30;
//max node
const int maxn = 550;
//max size
const int maxd = 130;
//max days

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 clear();
    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::clear()
{
    memset(head,-1,sizeof head);
    cur = 0;
    while (!q.empty()) q.pop();
    memset(vis,false,sizeof vis);
}

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 = 1000000000;
            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 f[maxd][maxd];

struct edge2
{
    int from,to,w;
};

edge2 data[maxn];
edge2 ban[maxn*5];
bool valid[maxm][maxd];
int dis[maxd][maxd];

bool judge(int from1,int to1,int from2,int to2)
{
    if (to1 <= from2) return true;
    if (from1 >= to2) return true;
    return false;
}

int main(int argc,char * argv[])
{
    int tagen,hafen,kes,e;
    cin >> tagen >> hafen >> kes >> e;
    for (int i = 0 ;i < e;++i)
    {
        cin >> data[i].from >> data[i].to >> data[i].w;
    }
    int d;
    cin >> d;
    CShortestSolver solver;
    memset(valid,true,sizeof(valid));
    for (int i = 0;i < d;++i)
    {
        cin >> ban[i].w >> ban[i].from >> ban[i].to;
        for (int j = ban[i].from;j <= ban[i].to;++j) valid[ban[i].w][j] = false;
    }
    for (int i = 1; i <= tagen;++i)
    {
        bool konnen[maxm];
        for (int j = 1;j <= hafen;++j) konnen[j] = valid[j][i];
        for (int j = i;j <= tagen;++j)
        {
            solver.clear();
            if (j != i) for (int k = 1;k <= hafen;++k) konnen[k] &= valid[k][j];
            for (int k = 0;k < e;++k) if (konnen[data[k].from] && konnen[data[k].to])
            {
                solver.addEdge(data[k].from, data[k].to, data[k].w);
                solver.addEdge(data[k].to, data[k].from, data[k].w);
            }
            dis[i][j] = solver.solve(1, hafen, hafen);
            if (dis[i][j] != 1000000000) dis[i][j] *= (j-i+1);
        }
    }
    for (int i = 1;i <= tagen;++i)
    {
        for (int j = i;j <= tagen;++j)f[i][j] = dis[i][j];
    }
    for (int i  = 2;i <= tagen;++i)
    {
        for (int j = 1;j <= tagen-i+1;++j)
        {
            int k = i+j-1;
            for (int l = j;l <= k;++l) if (f[j][l] + f[l+1][k] + kes < f[j][k]) f[j][k] = f[j][l] + f[l+1][k] + kes ;
        }
    }
    cout << f[1][tagen] << endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值