[kuangbin带你飞]专题四 最短路练习 R

时间:2023-02-13 19:54:59

http://acm.hdu.edu.cn/showproblem.php?pid=4370

HDU 4370 0 or 1(最短路)

这是整套里面我觉得最有意思的一道最短路,也确实让我觉得我与真正acmer之间的距离还是很大的

Problem Description
Given a n*n matrix Cij (1<=i,j<=n),We want to find a n*n matrix Xij (1<=i,j<=n),which is 0 or 1.

Besides,Xij meets the following conditions:

1.X12+X13+…X1n=1
2.X1n+X2n+…Xn-1n=1
3.for each i (1in), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n).

For example, if n=4,we can get the following equality:

X12+X13+X14=1
X14+X24+X34=1
X12+X22+X32+X42=X21+X22+X23+X24
X13+X23+X33+X43=X31+X32+X33+X34

Now ,we want to know the minimum of ∑Cij*Xij(1<=i,j<=n) you can get.

题意:

给你一个n*n的矩阵,然后让咱们构造另一个n*n的矩阵,构造的矩阵有如下要求,
1.X12+X13+…X1n=1.
2.X1n+X2n+…Xn-1n=1.
3.for each i (1 I n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n).

tip:

额。。这个题解写着好虚啊,毕竟不是自己想的。
究竟怎么就是最短路了呢?
首先啊,如果每行的数字都缩成一个点,且如果X(i,j) = 1 那么我们连边i->j,如果是0的话,乘cij之后和没有是一样的,所以不管他,那么 连边i->j什么意思呢?
第三个条件是,第i行的x和等于第i列x和对吧,那么从i出去多少条边就是第i行多少个1 ,也就是第i行的和,换句话说:i点的出度就是∑Xij 。
那么当X(i,j)=1时,第j列是不是出现了一个1?也就是说第j列的和:+1了。连边所以的i->j后,就是所有第几行第j列是1了,点j的入度自然就是第j列的和。

那么第三个条件就是: 2~n-1这些节点,满足:入度 = 出度!
第二个条件是 :n号节点的入度为1
第一个条件: 1号节点的出度为1

然后基于这个思想,每个边权值为c(i,j)
1->n的最短路就是答案,x为0的就是不选的边,下= 1的就是选的边,边的选择就交给最短路了,
这个时候,我又错了。。。
只考虑1->n是不行的,因为可能1->..->1中间没有n和n ->…->n这两个路放在一起是最小的,那么单纯的最短路就不对了咯。我们需要搞两种,在比较一下就好了,这个的处理就是之前的dist【1】先为无穷,所以1直接可达的点放队列,dijstra一下,就可以球出来1->1 1->n的最短路了,那么n->n呢?
我是选择了在一个dij,然后就ac了==

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 300*300+10;
const int maxm = 1e6+10;
int n,tot,head[maxn],dist[maxn],dis[maxn];
typedef pair<int,int>pii;
priority_queue<pii,vector<pii>,greater<pii> >q,p;
struct node{
int v,w,next;
}edges[maxm];

void add(int u,int v,int w){
edges[tot].v = v;edges[tot].w= w;edges[tot].next = head[u];head[u]=tot++;
}

void init(){
memset(head,-1,sizeof(head));
tot =0;
dist[1] = (1<<30);
dis[n] = (1<<30);
for(int i = 1 ; i <= n ; i++){
for(int j = 1 ; j <= n ; j++){
int w;
scanf("%d",&w);
add(i,j,w);
if(i == 1&&j!=1){
q.push(make_pair(w,j));
dist[j] = w;
}
if(i == n&&j!=n){
p.push(make_pair(w,j));
dis[j] = w;
}
}
}
}

void dij(){
while(!q.empty()){
pii tmp = q.top();
q.pop();
for(int k = head[tmp.second];k!=-1;k=edges[k].next){
if(dist[edges[k].v] > dist[tmp.second]+edges[k].w){
dist[edges[k].v] = dist[tmp.second]+edges[k].w;
q.push(make_pair(dist[edges[k].v],edges[k].v));
}
}
}
}
void di(){
while(!p.empty()){
pii tmp = p.top();
p.pop();
for(int k = head[tmp.second];k!=-1;k=edges[k].next){
if(dis[edges[k].v] > dis[tmp.second]+edges[k].w){
dis[edges[k].v] = dis[tmp.second]+edges[k].w;
p.push(make_pair(dis[edges[k].v],edges[k].v));
}
}
}
}


void sov(){
dij();
di();
printf("%d\n",min(dist[n],dist[1]+dis[n]));
}

int main(){
while(~scanf("%d",&n)){
init();
sov();
}
}