SP

来源:互联网 发布:虚幻引擎for mac 编辑:程序博客网 时间:2024/04/28 07:25
彻底没话讲了。。。好不容易码了三天的东西。。。结果今天玩游戏不小心把电脑给弄得太热,一个重启。。。我去啊。。。真是。。。太坑爹了。。。码的博客没了。。。chrome也坏了。然后又是忙了一周的社会实践,零零碎碎才有空抽出时间把SP又重新刷了一遍,社会实践结束了之后可要好好抓紧时间了啊。。。

。。有些找到的博客地址都没了。。。╮(╯▽╰)╭。。。只能很不爽的从头再来一遍了。。。
Dijkstra想法就不说了。。。其实是没心情说了。。。以后补充吧。。。现在只想把做过的题目先回顾一下。。。
来几道练手的题目,具体想法很简单,就是裸题
zoj1298/poj1135 zoj2750 zoj1053/poj1122zoj1655(我就记得这道题目里面有两个trick,卡了我半天,一个是可以是重边,二是图不一定是联通的)其余的题目有一个童鞋的博客介绍的很好,大家可以去看看。
http://blog.csdn.net/popopopolo/article/category/814774
这里面题目挺多的,打算到时候一个个再做一遍。
zoj1232
这道题目当时暑假曾经做过。。。大赖子赖过去了。。。现在回头看看还是有点难度的。
简单点的做法就是floyd+dp
poj1511/zoj2008
数据范围注意点就行,最终结果是long,而且用邻接矩阵会mle,所以还是模拟临界矩阵比较好。构建两个图,每条边的方向相反,然后两个Dijkstra就行。
poj1556
这道题目是计算几何+最短路。最短路很简单,只要把用计算几何的知识把图给构建出来就行了。首先分清楚有两类东西:墙和门;可以简化为线段和点。判断任意有意义的两点是否相连,就是判断该两点是否穿墙,其实从这个点来说,也不怎么考知识,稍微考点编码,就当一个小模拟吧,因为这个判断两点连线是否穿过线段初中就知道,方法很多,可以考虑斜率,可以考虑连线和线段的交点。判断两点之间是否有连线之后就很好做了,很裸的最短路。
poj1613
加上时间限制的最短路,看上去很复杂,其实只是就是在松弛的时候,dist[edge[i].v]>dist[u]+edge[i].val,这一步的时候,将dist[u]+edge[i].val,换成加上时间限制的最短距离。题

目还有一个trick,该图是双向边。因为这个wa了几次,因此做图论的时候,第一个要确定的是是双向边还是单向边。
poj3268
反向建边,裸题。
poj3259
SPFA判断是否有负权环的时候,就是判断一个点入队的时间是否>=n,也就是另外再开一个数组进行记录每个点入队次数即可。
zoj3088
全源最短最长路,自己做的时候没有注意到,都是先上升,然后再下降的顺序,而这不会交错。
poj2570
估计现在就是刷水题开心点了O(∩_∩)O哈!题目很水,Floyd就行,唯一注意的就是这道题目做法很多,但是二进制是最简单的,刚开始都没有想到。
poj2263poj2253
水题,就当练练模板吧。
zoj2027
这道题目被狠狠的坑了一把,竟然是HashMap忘记清空了。。。两种做法,都是先用Floyd求出任意两点的最短路,然后第一种,有点类似于zoj1323超级玛丽,用dp做,dp[n][2],dp[n][0]表示从1到n的点没有免费过的费用有多少,dp[n][1]表示从1到n免费过一次后的最短费用是多少,dp[i][0]=adj[1][i],假设有边(i,j),这个可以用一个数组进行标记,dp[j][1]=min(dp[j][1],dp[i][0],dp[i][1]+adj[i][j]),最后的dp[n][1]即为所求,当然有点类似于Floyd想法,这个整个o(n^2)的操作还要再进行n次来"扩充"到所有的缩短变能够连在一起,所以外面还要再套一个o(n)的循环。第二种,直接枚举每条边(i,j),取adj[1][i]+adj[j][2]最小的值即为所求,(n^2)就行。
poj2472
裸题,Floyd求最长即可。
poj1125 poj 1603
题目还是比较简单的,练练手。
但是看到网上一个很有趣的写法:
loop: for (inti = 0; i < t; i++) {
max =Integer.MIN_VALUE;
for (int j =0; j < t; j++) {
if (p[i][j] ==MAXVALUE) {
continueloop;
} else{
max =Math.max(max, p[i][j]);
}
}
if (max< min) {
min =max;
start =i;
}
}
poj2607
这道题目还好在poj上面只有一个测试样例,输入不算特别复杂,在zoj上面貌似输入就比较头大了。然后题目意思有一点很重要,枚举每个点i作为新的消防站的点的时候,题目意思是每个居民到最近的消防站的点最短距离的最大距离要缩短,直接上代码就是(这里fff这个变量命名不好,不过意思就是每个居民到消防站的最短距离)
int min = inf,max, fff, vertex = 1;
for (int i =1; i <= n; i++) {
if (point[i]== 0) {
max =0;
for (int j =1; j <= n; j++) {
if (point[j]== 0) {
fff =Integer.MAX_VALUE;
for (int k =1; k <= n; k++) {
if (point[k]== 1)
fff =Math.min(fff, adj[k][j]);
}
fff =Math.min(fff, adj[i][j]);
max =Math.max(max, fff);
}
}
if (max< min) {
min =max;
vertex =i;
}
}
}
当然用spfa之类的也是可以的。自己是卡在了每个居民到消防站的最短距离不一定是我们枚举到的点i,可以是其余的已经建好的消防站。
zoj2770  poj1201  poj1364  poj1275
裸的差分约束,练练模板吧。注意在运用过程中条件的代入和超级源点的掌握。
poj3169
这道题目发现在做的时候不需要设置超级源点,由于题目中已经明确说明了,所有奶牛都是按照编号排序的,可以直接从第一头奶牛开始入队SPFA,而后判断是否唯一,则是看dist[n]==inf是否成立。

hdu4511
这道题目是3.22编程马拉松出现的题目。当时没有来得及把这道题目A掉,而且貌似全场做出这道题目的人也是所有题目当中最少的,后来在段爷的指导下有了一个把这道题目赖过去的方法。还是Dijkstra方法,不过由于点数比较少,而且从我们解决的策略来看,用邻接矩阵会比较方便。
同正常的最短路求解不同,这道题目在进行松弛操作的时候,还需要进行判断他前面的几个点是否是题目当中不允许的路径,这个其实用一个哈希表存储一下就行,不过我用的是HashMap。
核心代码如下:
loop: for (int i = 1; i<= n; i++) {
if (visit[i]== 0 && adj[u][i] <inf && dist[i] >dist[u] + adj[u][i]) {
int temp = u,cnt = 0;
String str = u+ "," + i;
while(path[temp] != -1) {
cnt++;
if (cnt> 5)
continueloop;
temp =path[temp];
str = temp +"," + str;
if(map.containsKey(str))
continueloop;
}
dist[i] =dist[u] + adj[u][i];
path[i] =u;
}
}


DIjkstra
//邻接矩阵
static classDijkstra {
int n, inf =Integer.MAX_VALUE, adj[][];

Dijkstra(intn) {
this.n =n;
adj = newint[n + 1][n + 1];
for (int i =1; i <= n; i++)
Arrays.fill(adj[i], inf);
}

voidaddEdge(int u, int v, int val) {
adj[u][v] =val;
}

voidaddDoubleEdge(int u, int v, int val) {
adj[u][v] =adj[v][u] = val;
}

intdist[];
intpath[];

voidShortestPath(int source) {
dist = newint[n + 1];
path = newint[n + 1];
Arrays.fill(path, -1);
int visit[] =new int[n + 1];
Arrays.fill(visit, 0);
visit[source]= 1;
for (int i =1; i <= n; i++) {
dist[i] =adj[source][i];
if (dist[i]< inf)
path[i] =source;
}
path[source] =-1;
dist[source] =0;

int min,u;
for (int step= 1; step < n; step++) {
min =inf;
u =source;
for (int i =1; i <= n; i++) {
if (visit[i]== 0 && dist[i] <min) {
u =i;
min =dist[i];
}
}
visit[u] =1;
for (int i =1; i <= n; i++) {
if (visit[i]== 0 && adj[u][i] <inf
&& dist[i]> dist[u] + adj[u][i]) {
dist[i] =dist[u] + adj[u][i];
path[i] =u;
}
}
}
}
}


//数组模拟连接链表+优先队列优化
static classDijkstra {
int n, m,index = 0;
inthead[];
edgeedge[];
PriorityQueuequeue = new PriorityQueue();

Dijkstra(intn, int m) {
this.n =n;
head = newint[n + 1];
Arrays.fill(head, -1);
edge = newedge[m + 1];
index =0;
}

voidaddEdge(int u, int v, int val) {
index++;
edge[index] =new edge();
edge[index].v= v;
edge[index].val = val;
edge[index].next = head[u];
head[u] =index;
}

longShortestPath(int source) {
short visit[]= new short[n + 1];
int dist[] =new int[n + 1];
queue.add(newnode(source, source, 0));

nodetemp;
intv;
while(!queue.isEmpty()) {
temp =queue.poll();
v =temp.v;
if (visit[v]== 1)
continue;
visit[v] =1;
dist[v] =temp.val;
for (int i =head[v]; i != -1; i = edge[i].next) {
if(visit[edge[i].v] == 0)
queue
.add(newnode(v, edge[i].v, edge[i].val
+dist[v]));
}
}

long sum =0;
for (int i =1; i <= n; i++)
sum +=dist[i];
returnsum;
}
}

static classedge {
int v, next =-1, val;

edge(){
}

edge(int u,int v, int val) {
this.v =v;
this.val =val;
}
}

static classnode implements Comparable {
int u, v,val;

node(int u,int v, int val) {
this.u =u;
this.v =v;
this.val =val;
}

public intcompareTo(node o) {
if (this.val< o.val)
return-1;
else if(this.val > o.val)
return1;
return0;
}
}

Bellman_Ford
//邻接矩阵
static classBellman_Ford {
intn;
doubleadj[][], inf = Double.MAX_VALUE;

Bellman_Ford(int n) {
this.n =n;
adj = newdouble[n + 1][n + 1];
for (int i =1; i <= n; i++)
Arrays.fill(adj[i], inf);
}

voidaddEdge(int u, int v, double val) {
adj[u][v] =val;
}

doubleShortestPath(int source, int destination) {
double dist[]= new double[n + 1];
Arrays.fill(dist, inf);

dist[source] =0;
for (int step= 1; step < n; step++) {
for (int u =1; u <= n; u++) {
for (int j =1; j <= n; j++) {
if (adj[j][u]< inf && dist[j] +adj[j][u] < dist[u])
dist[u] =dist[j] + adj[j][u];
}
}
}

returndist[destination];
}
}

//数组模拟邻接链表
SPFA
static classSPFA {
int n, head[],index;
edgeedge[];
LinkedListqueue = new LinkedList();
int inQ[],path[], dist[], inf = Integer.MAX_VALUE;

SPFA(int n,int m) {
this.n =n;
head = newint[n + 1];
Arrays.fill(head, -1);
edge = newedge[m + 1];
index =0;
}

voidaddEdge(int u, int v, int val) {
index++;
edge[index] =new edge(v, val);
edge[index].next = head[u];
head[u] =index;
}

voidShortestPath(int source) {
queue.add(source);
dist = newint[n + 1];
Arrays.fill(dist, inf);
dist[source] =0;
inQ = newint[n + 1];
inQ[source] =1;
path = newint[n + 1];
Arrays.fill(path, -1);

intu;
while(!queue.isEmpty()) {
u =queue.poll();
inQ[u] =0;
for (int i =head[u]; i != -1; i = edge[i].next) {
if(dist[edge[i].v] > dist[u] + edge[i].val){
dist[edge[i].v] = dist[u] + edge[i].val;
path[edge[i].v] = u;
if(inQ[edge[i].v] == 0) {
inQ[edge[i].v]= 1;
queue.add(edge[i].v);
}
}
}
}
}
}

static classedge {
int v, val,next;

edge(int v,int val) {
this.v =v;
this.val =val;
}
}

差分约束(SPFA):
int count[];//记录每个点入队次数,大于n即为有负权环

booleanisOK(int source) {
queue.add(source);
dist = newint[n + 1];
Arrays.fill(dist, inf);
dist[source] =0;
inQ = newint[n + 1];
inQ[source] =1;
path = newint[n + 1];
Arrays.fill(path, -1);
count = newint[n + 1];
Arrays.fill(count, 0);
count[source]= 1;

intu;
while(!queue.isEmpty()) {
u =queue.poll();
inQ[u] =0;
if (count[u]> n)
returnfalse;
for (int i =head[u]; i != -1; i = edge[i].next) {
if(dist[edge[i].v] > dist[u] + edge[i].val){
dist[edge[i].v] = dist[u] + edge[i].val;
path[edge[i].v] = u;
if(inQ[edge[i].v] == 0) {
inQ[edge[i].v]= 1;
queue.add(edge[i].v);
count[edge[i].v]++;
}
}
}
}
returntrue;
}

0 0
原创粉丝点击