Loading

HDU - 4370 0 or 1 思维,最短路

给定n * n矩阵C ij(1 <= i,j <= n),我们要找到0或1的n * n矩阵X ij(1 <= i,j <= n)。
此外,X ij满足以下条件:
1.X 12 + X 13 + ... X 1n = 1
2.X 1n + X 2n + ... X n-1n = 1
3.对于每个i(1 <i <n),满足ΣXki(1 <= k <= n)=ΣXij(1 <= j <= n)。
例如,如果n = 4,我们可以得到以下等式:
X 12 + X 13 + X 14 = 1
X 14 + X 24 + X 34 = 1
X 12 + X 22 + X 32 + X 42 = X 21 + X 22 + X 23 + X 24
X 13 + X 23 + X 33 + X 43 = X 31 + X 32 + X 33 + X 34
现在,我们想知道你可以得到的最小ΣCij * X ij(1 <= i,j <= n)。

给定的性质可以想到以下等价变化:

   将xij转化为ij图的邻接矩阵。

   1号点在2-n中有一个为1,其余0,相当于出度为1,n号点同理,入度为1 。其余点随意。

   和C对应相乘相当于在C上找一条路径使得路径和最小。这样就转化成了最短路。

  考虑最短路满足的条件 1.1-n的最短路 2.1到1的一个环,n到n的一个环,两者的叠加。

  对于后者,只需要for一遍所有节点用已知的最短路维护即可,

int n, m;//n点数 m边数
struct edge { int v, w; edge(int a, int b) { v = a, w = b; } };//v终点,w边权
struct node {
    int id, dis;//id点编号 dis暂时距离
    node(int a, int b) { id = a, dis = b; }
    friend bool operator<(node a, node b) {
        return a.dis > b.dis;//每次让距离小出队
    }
};
vector<edge>e[maxn];
int dis[maxn];//记录最短路
bool done[maxn];//记录是否找到最短路
int Min1, Min2;


void dijkstra(int t) {
    int s = t;//s起点 根据情况改
    for (int i = 0; i <= n; i++) dis[i] = INF, done[i] = 0;
    dis[s] = 0;
    priority_queue<node>Q;
    Q.push(node(s, 0));
    while (!Q.empty()) {
        node u = Q.top(); Q.pop();
        if (done[u.id])continue;
        done[u.id] = 1;
        for (int i = 0; i < e[u.id].size(); i++) {//遍历邻居
            edge y = e[u.id][i];
            if (done[y.v])continue;
            if (dis[y.v] > y.w + dis[u.id]) {
                dis[y.v] = y.w + u.dis;
                Q.push(node(y.v, dis[y.v]));//更新最短路
            }
        }
    }
    if (t == 0) {
        for (int i = 0; i < n; i++) {
            if (i == t) continue;
            Min1 = min(Min1, dis[i] + e[i][t].w);
        }
    }
    else {
        for (int i = 0; i < n; i++) {
            if (i == t) continue;
            Min2 = min(Min2, dis[i] + e[i][t].w);
        }
    }
}


int main() {
    int res;
    int x;
    while (~scanf("%d", &n)) {
        Min1 = Min2 = INF;
        memset(e, 0, sizeof e);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) x = readint(), e[i].push_back(edge(j, x));
        }
        for (int i = 0; i < n; i++) e[i][i].w = INF;
        dijkstra(0);
        res = dis[n - 1];
        dijkstra(n - 1);
        printf("%d", min(res, (Min1 + Min2)));
        puts("");
    }
}

 

posted @ 2020-08-07 11:11  MQFLLY  阅读(76)  评论(0编辑  收藏  举报