题意:
给你一个二维矩阵让你创建一个新的二维矩阵X使得:
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).
求 ∑Cij*Xij(1<=i,j<=n)最小值
X12+X13+…+X1n=1。 ————————1的出度为1.
1必须要到2 3…n其中一个(只是一个)
X1n+X2n+…+Xn-1 n=1。
1 2 3…n-1 其中一个(只是一个)到n ——————n的入度为1.
第三个条件 到i的和从i出去的是相等的 emm我们就去想最短路…最短路的路径里面正好是一个点进一个点出…
比如。。从2到3,也会有从3到别的,假设到5,(2,3) (3,5)
这样 第3竖排 和 第3横排都有了一个相同的值 是1
可见是很有道理的。。。已知的C矩阵正好是邻接矩阵ma[i][j]的值代表 i到j的边长
此情况为2到n-1的所有点(前提是最短路径经过该点 有入度和出度的时候)入度和出度为1的情况(求1到n的最短路)
另一种是部分点入度和出度为0的情况
也就是1走一个环(不能自身成环) n走一个环(不能自身成环)
虚拟矩阵中走了哪条边就在该位置为1,自然(1,1)和(n,n)的位置都是0
这个题要求闭环 所以不能将起点入队 因为这样d[s]无法初始状态为INF了
dijkstra 和 spfa 的代码都贴一下
//----dijkstra
#include <queue>
#include <cstdio>
#define mak(a,b) make_pair(a,b)
#define pi pair<int,int>
using namespace std;
const int N=300+2;
const int INF=0x3f3f3f3f;
int head[N],d[N];
int tot,n;
struct Edge{int to,len,nex;}edge[N*N+2];
void add(int from,int to,int len)
{
edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
}
priority_queue<pi,vector<pi>,greater<pi> >q;
void dij(int s)
{
while(!q.empty())
q.pop();
for(int i=1;i<=n;i++)
d[i]=INF;
for(int i=head[s];i;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(y==s) //排除有s-s的边 这个边不为INF时 d[s]!=INF;
continue; //自然就没有求起点处闭环的作用了
d[y]=l;
if(l!=INF)
q.push(mak(d[y],y));
}
while(!q.empty())
{
int x=q.top().second;
q.pop();
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(d[y]>d[x]+l)
{
d[y]=d[x]+l;
q.push(mak(d[y],y));
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
head[i]=0;
tot=0;
int len;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&len);
add(i,j,len);
}
dij(1);
int ans1=d[n];//1到n的最短路 2--(n-1)的最短路里面的点入度出度为1
int op1=d[1];//1单独成环
dij(n);
int op2=d[n];//n单独成环
int ans2=op1+op2;//2--(n-1)的大部分点入度出度为0 环上的点入度为1
printf("%d\n",ans1<ans2?ans1:ans2);
}
}
//----spfa
#include <queue>
#include <cstdio>
#define mak(a,b) make_pair(a,b)
#define pi pair<int,int>
using namespace std;
const int N=300+2;
int ma[N][N],d[N];
bool vis[N];
queue<int>q;
int n;
void spfa(int s)
{
while(!q.empty())
q.pop();
for(int i=1;i<=n;i++)
{
if(i==s)
{
d[i]=INF;
vis[i]=0;
}
else if(ma[s][i]!=INF)
{
d[i]=ma[s][i];
q.push(i);
vis[i]=1;
}
else //一个小优化 假若INF加进去还要白白循环一边也不会更新任何值
{
d[i]=INF;
vis[i]=0;
}
}
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for(int y=1;y<=n;y++)
{
if(d[y]>d[x]+ma[x][y])
{
d[y]=d[x]+ma[x][y];
if(!vis[y])
{
q.push(y);
vis[y]=1;
}
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&ma[i][j]);
spfa(1);
int ans1=d[n];//1到n的最短路 2--(n-1)的入度出度为1
int op1=d[1];//1单独成环
spfa(n);
int op2=d[n];//n单独成环
int ans2=op1+op2;//2--(n-1)的入度出度为0
printf("%d\n",ans1<ans2?ans1:ans2);
}
}