Telephone Lines (POJ - 3662,SPFA + DP || 二分 + SPFA || 分层图 + SPFA)

一.题目链接:

POJ-3662

二.题目大意:

n 个点,p 条边的无向图.

最多可将图中的 k 条路权值变为 0,并定义该图的权值为 1 到 n 的所有选择方案中最大权值路的最小值.

求该图权值,如果 1 到 n 不存在路径,输出 -1.

三.分析:

① SPFA + DP

设 dis[v][k] 为从 1 到 v 的路径中选择了 k 条路权值为 0 的最短距离.

每次有两种方案:

1. 将该边的权值置为 0,即 dis[v][k] == dis[u][k].

2. 不对这条边进行处理,即 dis[v][k] == max(dis[u][k], Edge[i].w).

那么这就是 SPFA 中更新距离的核心.

详见代码.

② 二分 + SPFA

设该图权值为 mid,即从 1 到 n 所经过路中权值大于 mid 的路权值都要置为 0,即置为 0 路的个数应该小于等于 k.

设路权值大于 mid 的路的权值为 1,否则为 0,所求即 dis[n] <= k.

详见代码.

③ 分层图 + SPFA

分层图学习

四.代码实现:

① SPFA + DP

#include 
#include 
using namespace std;

const int M = (int)1e3;
const int inf = 0x3f3f3f3f;

int n, p, k;

int cnt;
int head[M + 5];
struct node
{
    int v, w, nx;
}Edge[M * 20 + 5];

bool vis[M + 5];
int dis[M + 5][M + 5];

void init()
{
    cnt = 0;
    for(int i = 1; i <= n; ++i)
    {
        vis[i] = 0;
        head[i] = -1;
        for(int j = 0; j <= k; ++j)
            dis[i][j] = inf;
    }
}

void add(int u, int v, int w)
{
    Edge[cnt].v = v;
    Edge[cnt].w = w;
    Edge[cnt].nx = head[u];
    head[u] = cnt++;
}

void spfa(int s)
{
    queue  q;
    q.push(s);
    vis[s] = 1, dis[s][0] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = Edge[i].nx)
        {
            int v = Edge[i].v;
            if(dis[v][0] > max(dis[u][0], Edge[i].w))
            {
                dis[v][0] = max(dis[u][0], Edge[i].w);
                if(!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
            for(int j = 1; j <= k; ++j)
            {
                if(dis[v][j] > min(dis[u][j - 1], max(dis[u][j], Edge[i].w)))
                {
                    dis[v][j] = min(dis[u][j - 1], max(dis[u][j], Edge[i].w));
                    if(!vis[v])
                    {
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
}

int main()
{
    scanf("%d %d %d", &n, &p, &k);
    init();
    for(int i = 0, u, v, w; i < p; ++i)
    {
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w);
        add(v, u, w);
    }
    spfa(1);
    int ans = inf;
    for(int i = 0; i <= k; ++i)
        ans = min(ans, dis[n][k]);
    if(ans == inf)  ans = -1;
    printf("%d\n", ans);
    return 0;
}

② 二分 + SPFA

#include 
#include 
#include 
//#include 
using namespace std;

const int M = (int)1e3;
const int inf = 0x3f3f3f3f;

int n, p, k;

int cnt;
int head[M + 5];
struct node
{
    int v, w, nx;
}Edge[M * 20 + 5];

int dis[M + 5];
bool vis[M + 5];

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void add(int u, int v, int w)
{
    Edge[cnt].v = v;
    Edge[cnt].w = w;
    Edge[cnt].nx = head[u];
    head[u] = cnt++;
}

struct cmp
{
    bool operator()(int a, int b)
    {
        return dis[a] > dis[b];
    }
};

priority_queue , cmp> q;

void spfa(int s, int mid)
{
    memset(vis, 0, sizeof(vis));
    memset(dis, inf, sizeof(dis));
    q.push(s);
    vis[s] = 1, dis[s] = 0;
    while(!q.empty())
    {
        int u = q.top();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = Edge[i].nx)
        {
            int v = Edge[i].v, w = (Edge[i].w > mid);
            if(dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                if(!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    scanf("%d %d %d", &n, &p, &k);
    init();
    for(int i = 0, u, v, w; i < p; ++i)
    {
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w);
        add(v, u, w);
    }
    int l = 0, r = inf, mid;
    while(l < r)
    {
        mid = (l + r) >> 1;
        spfa(1, mid);
        if(dis[n] <= k)
            r = mid;
        else
            l = mid + 1;
    }
    if(r == inf)    r = -1;
    printf("%d\n", r);
    return 0;
}

③ 分层图 + SPFA

#include 
#include 
using namespace std;

const int M = (int)1e6;
const int inf = 0x3f3f3f3f;

int n, p, k;

int cnt;
int head[M + 5];
struct node
{
    int v, w, nx;
}Edge[M * 5];

int dis[M + 5];
bool vis[M + 5];

void init()
{
    cnt = 0;
    for(int i = 1; i <= M; ++i)
    {
        vis[i] = 0;
        head[i] = -1;
        dis[i] = inf;
    }
}

void add(int u, int v, int w)
{
    Edge[cnt].v = v;
    Edge[cnt].w = w;
    Edge[cnt].nx = head[u];
    head[u] = cnt++;
}


struct cmp
{
    bool operator()(int a, int b)
    {
        return dis[a] > dis[b];
    }
};

priority_queue , cmp> q;

void spfa(int s)
{
    q.push(s);
    vis[s] = 1, dis[s] = 0;
    while(!q.empty())
    {
        int u = q.top();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = Edge[i].nx)
        {
            int v = Edge[i].v;
            if(dis[v] > max(dis[u], Edge[i].w))
            {
                dis[v] = max(dis[u], Edge[i].w);
                if(!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    scanf("%d %d %d", &n, &p, &k);
    init();
    for(int i = 1, u, v, w; i <= p; ++i)
    {
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w);
        add(v, u, w);
        for(int j = 1; j <= k; ++j)
        {
            add(u + j * n, v + j * n, w);
            add(v + j * n, u + j * n, w);
            add(u + (j - 1) * n, v + j * n, 0);
            add(v + (j - 1) * n, u + j * n, 0);
        }
    }
    for(int i = 1; i <= k; ++i)
        add(i * n, (i + 1) * n, 0);
    spfa(1);
    printf("%d\n", dis[(k + 1) * n] == inf ? -1 : dis[(k + 1) * n]);
    return 0;
}

 

你可能感兴趣的:(#,二分,#,线型,DP,#,分层图)