HDU 4370:
这一题网上题解很多,不过都很精简。我就写一个详细的吧
原题连接:
http://acm.hdu.edu.cn/showproblem.php?pid=4370
题目中的三个条件:
∑i=2nX1 , i=1∑i=1n−1Xi , n=1∑k=1nXi, k=∑k=1nXk, i i∈[2,n−1]
第三个条件非常有意思,限制了矩阵
X
的行和列 .
第三个条件给的很隐晦。它隐含了一些信息。
(当然有经验的人就不觉得隐晦了。 因人而异吧 。有人会觉得这是一个很明显的暗示)
假设:开始的时候 。X中所有元素为 0
如果我们给 :
那么也有:
∑k=1nX[c][k]=∑k=1nX[k][c]=1
此时。我们必须选择一个t.令 X[c][t]=1 且 c≠t
为了维护性质我们似乎要更改一连串的位置。
这是我最初想到的。这样的选择会重复下去。
我们记录更改的下标。那么会有:
[r][c]−>[c][t]
如果我们继续更改位置。或许会有:
[r][c]−>[c][t]−>[t][p]
什么时候能停能:
例如:
[r][c]−>[c][t]−>[t][p]−>[p][r]
当然上面可以停,也可以不停止。因为对于行和列的限制并不一定是1.
看上去。上面像一条路径。
我们似乎可以把
X
看作邻接矩阵
如果条件 3 转化为每个点的出度等于入度。
很明显。惊奇的发现。
(说真的。想到这里。想了很久。开始是想这个题目或许是构造的)
因为 条件3 对 点1和n 不起作用。 在不经过1与n的路径中。必然会走一条欧拉回路,或者没有路(行列 的 限制为 0 的时候)
欧拉回路是可以一笔画成的回路。 你可以理解成。他是一个圆环。被扭转在一起。路线之间会有交点。 这个交点就是重复走过的点。但是每个路线边只允许走一次。路径上不允许有重复走过的长度。(数学上。点是没有长度和面积的)
我们把 C[i][j] 看作 i−−> j这条边的长度
那么最短的回路: 必然是独立的环 或者 一条简单路 (扭在一起多走的环。必然增加答案)
通过上面的分析。限制:
每个点的:出度=入度<=1
就可以得到 答案。
这个限制也包含 点1 与 点 n 这是因为。总出度=总入度。
而点1点出度被限制。 点 n的入度被限制。
到这里。基本快要解决问题了。但我们还没有交代清楚。
题目中还有两个条件:
∑i=2nX1 , i=1∑i=1n−1Xi , n=1
这个条件比较有趣。他是不受条件3限制。
这也就是说 。
第1行的出度是1,入度不做限制。第n列的入度为1,出度不作限制。
那么我们就要分类讨论。
很明显。第 1 个节点 的 入度要 和 第 n 个节点的出度保持一致。
这是因为:
总出度 等于 总入度。 又因为两个点的出度和入度被限制。
点1的入度=点n的出度。
其他点的出度=入度
所以 点1的 入度 与 点n 的出度保持一致。
这样才可以使的:总出度=总入度
那么答案有两种情况:
第1种:1−−>n的最短路。第2种:一个经过1的环和一个经过n的环
对于第二种情况:
我们记 从1出发。环经过的最后一个点事 A 枚举 A
环的长度就是 dis1[A]+C[A][1] ;
从n出发。环的最后一个点事 B。枚举B
环的长度就是 dis2[B]+C[B][n]
其中
dis1[A]是A到1的距离dis2[B]是B到n的距离
tmp=mini∈[2,n]且j∈[1,n−1](dis1[i]+C[i][1]+dis2[j][n]+C[j][n])
answer=min(tmp,dis1[n])
将C作为图来计算两种距离 dis1, dis2
下面是代码:
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <vector>
#define MAXN 305
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
int n;
int C[MAXN][MAXN];
int dis1[MAXN];
int dis2[MAXN];
priority_queue<P,vector<P>,greater<P>>Q;
void init();
void spfa(int s,int *dis,int edge[][MAXN])
{
dis[s]=0;
Q.push(P(0,s));
while(!Q.empty())
{
P x=Q.top(); Q.pop();
if(x.first>dis[x.second])continue;
int v=x.second;
int d=x.first;
for(int i=0;i<n;i++)
{
int w=d+edge[v][i];
if(w>=dis[i])continue;
dis[i]=w;
Q.push(P(dis[i],i));
}
}
}
int main ()
{
while(scanf("%d",&n)==1&&n)
{
init();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",C[i]+j);
spfa(0 , dis1, C);
spfa(n-1, dis2, C);
int ans=dis1[n-1];
for(int i=1;i<n;i++)
for(int j=0;j<n-1;j++)
ans=min(ans,dis1[i]+C[i][0]+dis2[j]+C[j][n-1]);
printf("%d\n",ans);
}
return 0;
}
void init()
{
memset(dis1,0x3f,sizeof dis1);
memset(dis2,0x3f,sizeof dis2);
}