kuangbin带你飞 最短路 题解
求一个图最短路边的办法。好像下面的那个有问题。单向边和双向边一定是有区别的。这个比较容易。参照该文的最短路网络流题目和连通图题目一题求最短路关节边
另外上述2个题目的代码好像有问题。
在UVALIVE 6885中不能得到AC。不知道原因。感觉是对的。
另一种判断最短路的方法就是
从起点到u+从终点到v+边U,V权值==最短路值那么这条边为最短路
这种方案的代码
for (int i = ; i <= M ; i++) {
scanf("%d%d%d",&u[i],&v[i],&w[i]);
u[i]++;v[i]++;
S.add_edge(u[i],v[i],w[i],i);
S.add_edge(v[i],u[i],w[i],i);
T.add_edge(u[i],v[i],w[i],i);
T.add_edge(v[i],u[i],w[i],i);
}
S.dijkstra(source);
T.dijkstra(target);
long long ans = ;
for (int i = ; i <= P ; i++) {
for (int j = S.head[i] ; j != - ; j = S.edge[j].next) {
int v = S.edge[j].v;
if (S.dis[i] + T.dis[v] + S.edge[j].w == S.dis[target])
//这条边为最短路边
}
}
同时另一种可能存在问题的方法如下
for (int i = ; i <= m ; i++)
{
scanf("%d%d%I64d",&u[i],&v[i],&w[i]);
S.add_edge(u[i],v[i],w[i],i);
S.add_edge(v[i],u[i],w[i],i);
T.add_edge(u[i],v[i],w[i],i);
T.add_edge(v[i],u[i],w[i],i);
}
S.dijkstra(s);
T.dijkstra(t);
init();
for (int i = ; i <= m ; i++)
{
int tu = u[i];
int tv = v[i];
LL tw = w[i];
if ((S.dis[tu] + tw == S.dis[tv] && T.dis[tv] + tw == T.dis[tu])
||(S.dis[tv] + tw == S.dis[tu] && T.dis[tu] + tw == T.dis[tv]))
{
add_edge(tu,tv,tw,i);
add_edge(tv,tu,tw,i);//这里是为了处理tarjan无向图 其实就是u[i],v[i],w[i]这条边为最短路边。
}
}
slove(n);
对于上述方案的有向图 建图有区别
如下
for (int i = ; i < M ; i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
St.add_edge(u[i],v[i],w[i],i + );
//St.add_edge(v[i],u[i],w[i],i + 1);
//Ted.add_edge(u[i],v[i],w[i],i + 1);
Ted.add_edge(v[i],u[i],w[i],i + );
}
scanf("%d%d",&A,&B);
St.dijkstra(A);
/* if (St.dis[B] == INF)
{
puts("0");
continue;
}
*/
Ted.dijkstra(B);
for (int i = ; i < M ; i++)
{
int tu = u[i];
int tv = v[i];
int tw = w[i];
if (tu == tv) continue;
if ((St.dis[tu] + tw == St.dis[tv] && Ted.dis[tv] + tw == Ted.dis[tu])
||(St.dis[tv] + tw == St.dis[tu] && Ted.dis[tu] + tw == Ted.dis[tv]))
{
add_edge(tu,tv,);//这里添加的是网络流的边无需双向
}
}
POJ 2387 Til the Cows Come Home
直接求最短路末班题。我这里是dijkstra+优先队列优化的班
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int head[MAXN],tot; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} struct heapnode
{
int val,u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; bool done[MAXN];
int dis[MAXN];
priority_queue<heapnode>q;
int N,M; void dijkstra(int s)
{
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
memset(dis,0x3f,sizeof(dis));
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
swap(N,M);
init();
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
dijkstra();
printf("%d\n",dis[N]);
}
return ;
}
POJ 2253 Frogger
从1号点跳到2号点所经过的路径中最短的路径长度
可以用类似最小生成树的思路来解
这里用的kruskal
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
struct Edge
{
int u,v;
double w;
friend bool operator <(const Edge &a,const Edge &b)
{
return a.w < b.w;
}
}edge[MAXM];
int fa[MAXN],tot,N;
double x[MAXN],y[MAXN];
int Find(int x) {return x == fa[x] ? x : fa[x] = Find(fa[x]);} bool judge()
{
int fu = Find();
int fv = Find();
if(fu == fv) return true;
return false;
} void build()
{
tot = ;
for (int i = ; i <= N ; i++)scanf("%lf%lf",&x[i],&y[i]);
for (int i = ; i <= N ; i++)
{
for (int j = i + ; j <= N ; j++)
{
double dis = sqrt((x[i] - x[j]) * (x[i] - x[j]) +
(y[i] - y[j]) * (y[i] - y[j]));
edge[tot].u = i;
edge[tot].v = j;
edge[tot].w = dis;
tot++;
}
}
} double kruskal()
{
int cnt = ;
double ret = 0.0;
sort(edge,edge + tot);
for (int i = ; i <= N ; i++) fa[i] = i;
for (int i = ; i < tot ; i++)
{
if (judge()) return ret;
int fu = Find(edge[i].u);
int fv = Find(edge[i].v);
if (fu != fv)
{
fa[fu] = fv;
cnt++;
ret = max(ret,edge[i].w);
}
}
return ret;
} int main()
{
//freopen("sample.txt","r",stdin);
int kase = ;
while (scanf("%d",&N) != EOF)
{
if (N == ) break;
printf("Scenario #%d\nFrog Distance = ",kase++);
build();
printf("%.3f\n",kruskal());
putchar('\n');
}
return ;
}
另一种建立在理解dijkstra的基础上的代码。根据题意来确定相关更新
实际上这套题最困扰我的就是这几个dijkstra思想的题目。太弱。。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const double INF = 1e12;
struct node
{
double x,y;
}src[MAXN];
double dis[MAXN];
bool vis[MAXN];
int N; double dist(node a,node b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
} void dijkstra()
{
memset(vis,false,sizeof(vis));
for (int i = ; i < MAXN ; i++) dis[i] = INF * 1.0;
dis[] = 0.0;
for (int i = ; i <= N ; i++)
{
double mincost = INF;
int pos = - ;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && dis[j] < mincost)
{
mincost = dis[j];
pos = j;
}
}
if (pos == -) return;
vis[pos] = true;
if (pos == ) return;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && dis[j] > max(dis[pos],dist(src[pos],src[j])))
dis[j] = max(dis[pos],dist(src[pos],src[j]));
}
}
} int main()
{
int kase = ;
while (scanf("%d",&N) != EOF)
{
if (N == ) break;
for (int i = ; i <= N ; i++) scanf("%lf%lf",&src[i].x,&src[i].y);
dijkstra();
printf("Scenario #%d\nFrog Distance = %.3f\n\n",kase++,dis[]);
}
return ;
}
POJ 1797 Heavy Transportation
一号点到N号点的合法路径中最小的边的最大值 ,这个实际就是最大生成树。直接kruskal很容易
这里还是要用下dijkstra和prim来区分一下。
下面这里是别人博客的一段话
在图论中,Prim算法是计算最小生成树的算法,而Dijkstra算法是计算最短路径的算法。二者看起来比较类似,因为假设全部顶点的集合是V,已经被挑选出来的点的集合是U,那么二者都是从集合V-U中不断的挑选权值最低的点加入U,那么二者是否等价呢?也就是说是否Dijkstra也可以计算出最小生成树而Prim也可以计算出从第一个顶点v0到其他点的最短路径呢?答案是否定的,否则就不必有两个算法了。
二者的不同之处在于“权值最低”的定义不同,Prim的“权值最低”是相对于U中的任意一点而言的,也就是把U中的点看成一个整体,每次寻找V-U中跟U的距离最小(也就是跟U中任意一点的距离最小)的一点加入U;而Dijkstra的“权值最低”是相对于v0而言的,也就是每次寻找V-U中跟v0的距离最小的一点加入U。
一个可以说明二者不等价的例子是有四个顶点(v0, v1, v2, v3)和四条边且边值定义为(v0, v1)=20, (v0, v2)=10, (v1, v3)=2, (v3, v2)=15的图,用Prim算法得到的最小生成树中v0跟v1是不直接相连的,也就是在最小生成树中v0v1的距离是v0->v2->v3->v1的距离是27,而用Dijkstra算法得到的v0v1的距离是20,也就是二者直接连线的长度。
第一份是dijkstra的
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
int dis[MAXN][MAXN];
int N,M;
bool vis[MAXN];
int d[MAXN]; void dijkstra()
{
memset(vis,false,sizeof(vis));
memset(d,,sizeof(d));
for (int i = ; i <= N ; i++) d[i] = dis[][i];
for (int i = ; i <= N ; i++)
{
int maxcost = - ;
int pos = -;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] > maxcost)
{
maxcost = d[j];
pos = j;
}
}
if (pos == -) return;
if (pos == N) return;
vis[pos] = true;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] < min(d[pos],dis[pos][j]))
d[j] = min(d[pos],dis[pos][j]);
}
}
} int main()
{
int kase = ;
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
memset(dis,,sizeof(dis));
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
dis[u][v] = dis[v][u] = w;
}
printf("Scenario #%d:\n",kase++);
dijkstra();
printf("%d\n\n",d[N]);
}
return ;
}
第二份是prim的。仔细比对就发现差异
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
int dis[MAXN][MAXN];
int N,M,ans;
bool vis[MAXN];
int d[MAXN]; void dijkstra()
{
memset(vis,false,sizeof(vis));
memset(d,,sizeof(d));
for (int i = ; i <= N ; i++) d[i] = dis[][i];
d[] = ;
vis[] = true;
ans = INF;
for (int i = ; i <= N ; i++)
{
int maxcost = - ;
int pos = -;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] > maxcost)
{
maxcost = d[j];
pos = j;
}
}
if (pos == -) return;
ans = min(ans,maxcost);
if (pos == N) return;
vis[pos] = true;
for (int j = ; j <= N ; j++)
{
if (!vis[j] && d[j] < dis[pos][j])
d[j] = dis[pos][j];
}
}
} int main()
{
int kase = ;
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&N,&M);
memset(dis,,sizeof(dis));
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
dis[u][v] = dis[v][u] = w;
}
printf("Scenario #%d:\n",kase++);
dijkstra();
printf("%d\n\n",ans);
}
return ;
}
POJ 3268 Silver Cow Party
有向图中从所有点到A点,再所有点从A点回到原本位置,问其中这些路径中最长的是哪个。
所有点从A回到原点是一次单元最短路即可。另一半怎么做。建反图,再从A求一次最短路,详情代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const LL INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
LL w;
}edge[MAXM],res[MAXN];
int head[MAXN],tot;
int N,M,X; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} bool done[MAXN];
LL dis[][MAXN];
struct heapnode
{
LL val;
int u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; void dijkstra(int s,int id)
{
memset(dis[id],0x3f,sizeof(dis[id]));
memset(done,false,sizeof(done));
priority_queue<heapnode>q;
dis[id][s] = ;
q.push((heapnode){dis[id][s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
//printf("%d %d\n",u,dis[id][u]);
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[id][v] > dis[id][u] + edge[i].w)
{
dis[id][v] = dis[id][u] + edge[i].w;
q.push((heapnode){dis[id][v],v});
}
}
}
} void slove()
{
//memset(dis,0x3f,sizeof(dis));
for (int i = ; i < M ; i++)
{
scanf("%d%d%I64d",&res[i].u,&res[i].v,&res[i].w);
}
init();
for (int i = ; i < M ; i++)
add_edge(res[i].u,res[i].v,res[i].w);
dijkstra(X,);
init();
for (int i = ; i < M ; i++)
add_edge(res[i].v,res[i].u,res[i].w);
dijkstra(X,);
LL ret = ;
for (int i = ; i <= N ; i++)
{
if (i == X || dis[][i] == INF || dis[][i] == INF) continue;
ret = max(ret,dis[][i] + dis[][i]);
}
printf("%I64d\n",ret);
} int main()
{
while (scanf("%d%d%d",&N,&M,&X) != EOF)
{
slove();
}
return ;
}
POJ 1860 Currency Exchange
如何判断正环。这里2分代码。第一份spfa
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
struct Edge
{
int u,v,next;
double rate,commission;
}edge[MAXM];
int head[MAXN],tot;
int N,M,S;
double val; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,double rate,double commission)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].rate = rate;
edge[tot].commission = commission;
edge[tot].next = head[u];
head[u] = tot++;
} double dis[MAXN];
bool inq[MAXN];
int cnt[MAXN];
queue<int>q;
bool spfa(int s)
{
while (!q.empty()) q.pop();
for (int i = ; i <= N ; i++) dis[i] = -;
memset(inq,false,sizeof(inq));
memset(cnt,,sizeof(cnt));
q.push(s);
dis[s] = val;
inq[s] = true;
cnt[s] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
double rate = edge[i].rate;
double commission = edge[i].commission;
double price = (dis[u] - commission) * rate;
if (price > dis[v])
{
dis[v] = price;
if (!inq[v])
{
q.push(v);
cnt[v]++;
inq[v] = true;
}
if (cnt[v] >= N) return true;
}
}
if (dis[S] > val) return true;
}
return false;
} int main()
{
while (scanf("%d%d%d%lf",&N,&M,&S,&val) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int a,b;
double rab,cab,rba,cba;
scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
add_edge(a,b,rab,cab);
add_edge(b,a,rba,cba);
}
bool flag = spfa(S);
if (flag) puts("YES");
else printf("NO\n");
}
return ;
}
第二份bellman_ford
注意迭代的次数为N-1,判断是否还正环和原本的一样、枚举边来松弛
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
int N,M,S;
double val;
int tot;
double dis[MAXN];
struct Edge
{
int u,v;
double r,c;
}edge[MAXM]; bool bellman_ford()
{
memset(dis,,sizeof(dis));
dis[S] = val;
bool flag;
for (int i = ; i <= N - ; i++)
{
flag = false;
for (int j = ; j < tot ; j++)
{
if (dis[edge[j].v] < (dis[edge[j].u] - edge[j].c) * edge[j].r)
{
dis[edge[j].v] = (dis[edge[j].u] - edge[j].c) * edge[j].r;
flag = true;
}
}
if (!flag) break;
} for (int i = ; i < tot ; i++)
{
if (dis[edge[i].v] < (dis[edge[i].u] - edge[i].c) * edge[i].r)
return true;
}
return false;
} int main()
{
while (cin >> N >> M >> S >> val)
{
tot = ;
for (int i = ; i < M ; i++)
{
int a,b;
double rab,cab,rba,cba;
cin >> a >> b >> rab >> cab >> rba >> cba;
edge[tot].u = a;
edge[tot].v = b;
edge[tot].r = rab;
edge[tot].c = cab;
tot++;
edge[tot].u = b;
edge[tot].v = a;
edge[tot].r = rba;
edge[tot].c = cba;
tot++;
}
if (bellman_ford()) puts("YES");
else puts("NO");
}
return ; }
POJ 3259 Wormholes
判负环 同样2种代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot;
int N,M,W; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} bool inq[MAXN];
queue<int>q;
int cnt[MAXN];
int dis[MAXN];
bool SPFA()
{
while (!q.empty()) q.pop();
for (int i = ; i <= N ; i++)
{
dis[i] = INF;
q.push(i);
cnt[i] = ;
inq[i] = true;
}
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if(dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
q.push(v);
cnt[v]++;
}
if (cnt[v] >= N) return true;
}
}
}
return false;
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
init();
scanf("%d%d%d",&N,&M,&W);
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
for (int i = ; i < W ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,-w);
}
if (SPFA()) puts("YES");
else puts("NO");
}
return ;
}
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int tot;
int N,M,W; int dis[MAXN];
bool bellman_ford()
{
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[] = ;
for (int i = ; i <= N - ; i++)
{
for (int j = ; j < tot ; j++)
{
int u = edge[j].u;
int v = edge[j].v;
int w = edge[j].w;
if (dis[u] < INF && dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
}
}
}
for (int i = ; i < tot ; i++)
{
int u = edge[i].u;
int v = edge[i].v;
int w = edge[i].w;
if (dis[u] < INF && dis[v] > dis[u] + w)
return true;
}
return false;
} int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&N,&M,&W);
tot = ;
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
tot++;
edge[tot].v = u;
edge[tot].u = v;
edge[tot].w = w;
tot++;
}
for (int i = ; i < W ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = -w;
tot++;
}
if (bellman_ford()) puts("YES");
else puts("NO");
}
return ;
}
POJ 1502 MPI Maelstrom
阅读题,floyd做
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
int dp[MAXN][MAXN];
int N; void slove()
{
for (int k = ; k <= N ; k++)
{
for (int i = ; i <= N; i++)
for (int j = ; j <= N ; j++)
{
dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j]);
}
}
int ret = ;
for (int i = ; i <= N ; i++)
ret = max(dp[][i],ret);
printf("%d\n",ret);
} int main()
{
while (scanf("%d",&N) != EOF)
{
dp[][] = ;
for (int i = ; i <= N ; i++)
{
dp[i][i] = ;
for (int j = ; j <= i - ; j++)
{
char tmp[];
scanf("%s",tmp);
if (tmp[] == 'x') dp[i][j] = INF;
else dp[i][j] = atoi(tmp);
dp[j][i] = dp[i][j];
}
}
slove();
}
return ;
}
POJ 3660 Cow Contest
题意:给出了一系列比赛结果。比如其中一场比赛描述为A.B 说明A的能力值大于B。问最后有几个人的能力值的排名可以根据这几场比赛完全确定。floyd传递闭包
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
bool dp[MAXN][MAXN];
int main()
{
int N,M;
while (scanf("%d%d",&N,&M) != EOF)
{
memset(dp,false,sizeof(dp));
for (int i = ; i <= M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
dp[u][v] = true;
}
for (int k = ; k <= N ; k++)
for (int i = ; i <= N ; i++)
for (int j = ; j <= N ; j++)
if (dp[i][k] && dp[k][j]) dp[i][j] = true;
int ret = ;
for (int i = ; i <= N ; i++)
{
int cnt = ;
for (int j = ; j <= N ; j++)
cnt += dp[i][j] + dp[j][i];
if (cnt == N - ) ret++;
}
printf("%d\n",ret);
}
return ;
}
POJ 2240 Arbitrage
字符串map处理一下,然后直接floyd处理即可
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const double eps = 1e-;
double dp[MAXN][MAXN];
int N;
map<string,int>mp;
int main()
{
// freopen("sample.txt","r",stdin);
int kase = ;
while (scanf("%d",&N) != EOF)
{
if (N == ) break;
mp.clear();
char str[],tmp[];
int cas = ;
for (int i = ; i < N ; i++)
{
scanf("%s",str);
if (!mp[str]) mp[str] = cas++;
}
int M;
for (int i = ; i <= N ; i++)
{
for (int j = ; j <= N ; j++)
dp[i][j] = 0.0;
}
for (int i = ; i <= N ; i++)
dp[i][i] = 1.0; scanf("%d",&M);
for (int i = ; i < M ; i++)
{
double x;
scanf("%s%lf%s",str,&x,tmp);
int l = mp[str];
int r = mp[tmp];
dp[l][r] = max(dp[l][r],x);
}
for (int k = ; k <= N ; k++)
{
for (int i = ; i <= N ; i++)
for (int j = ; j <= N ; j++)
dp[i][j] = max(dp[i][j],dp[i][k] * dp[k][j]);
}
double ret = 0.0;
for (int i = ; i <= N ; i++)
ret = max(ret,dp[i][i]);
if (ret - 1.0 > eps) printf("Case %d: Yes\n",kase++);
else printf("Case %d: No\n",kase++);
}
return ;
}
POJ 1511 Invitation Cards
题目大意:给出n个点和n条有向边,求所有点到源点1的来回最短路之和(保证每个点都可以往返源点1)
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const LL INF = 1e17;
int P,Q;
struct Edge
{
int u,v,next;
LL w;
}edge[MAXN]; struct heapnode
{
LL val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijkstra
{
int N,M;
Edge edge[MAXM];
int tot ,head[MAXN];
LL dis[MAXN];
bool done[MAXN];
priority_queue<heapnode>q; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
while (!q.empty()) q.pop();
memset(done,false,sizeof(done));
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}first,second; int main()
{
int T,kase = ;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&P,&Q);
for (int i = ; i < Q ; i++)
{
scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);
}
first.init(P,Q);
for (int i = ; i < Q ; i++)
{
first.add_edge(edge[i].u,edge[i].v,edge[i].w);
}
first.dijkstra();
second.init(P,Q);
for (int i = ; i < Q ; i++)
{
second.add_edge(edge[i].v,edge[i].u,edge[i].w);
}
second.dijkstra();
LL ret = ;
for (int i = ; i <= P ; i++)
ret = ret + first.dis[i] + second.dis[i];
printf("%I64d\n",ret);
}
return ;
}
POJ 3159 Candies
差分约束+SPFA
给n个人派糖果,给出m组数据,每组数据包含A,B,c 三个数,
意思是A的糖果数比B少的个数不多于c,即B的糖果数 - A的糖果数<= c 。
最后求n 比 1 最多多多少糖果。
贴一下kuangbin神的题解吧
【解题思路】
这是一题典型的差分约束题。不妨将糖果数当作距离,把相差的最大糖果数看成有向边AB的权值,
我们得到 dis[B]-dis[A]<=w(A,B)。看到这里,我们联想到求最短路时的松弛技术,
即if(dis[B]>dis[A]+w(A,B), dis[B]=dis[A]+w(A,B)。
即是满足题中的条件dis[B]-dis[A]<=w(A,B),由于要使dis[B] 最大,
所以这题可以转化为最短路来求。
这题如果用SPFA 算法的话,则需要注意不能用spfa+queue 来求,会TLE ,而是用 spfa + stack
我自己直接dijkstra+优先队列是可以的。2个都贴一下
dijkstra
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const LL INF = 1e17;
int N,M;
struct Edge
{
int u,v,next;
LL w;
}; struct heapnode
{
LL val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijksta
{
int N,M;
int head[MAXN],tot;
Edge edge[MAXM];
bool done[MAXN];
LL dis[MAXN];
priority_queue<heapnode>q; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// cout << u << " " << dis[u] << endl;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
src.init(N,M);
for (int i = ; i < M ; i++)
{
int u,v;
LL w;
scanf("%d%d%I64d",&u,&v,&w);
src.add_edge(u,v,w);
}
src.dijkstra();
printf("%I64d\n",src.dis[N]);
}
return ;
}
spfa + stack
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int head[MAXN],tot;
struct Edge
{
int u,v,next;
int w;
}edge[MAXM];
int N,M; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} bool inq[MAXN];
int Stack[MAXN + MAXN];
int top;
int dis[MAXN];
void Spfa(int s)
{
int top = ;
for (int i = ; i <= N ; i++) dis[i] = INF;
memset(inq,false,sizeof(inq));
inq[s] = true;
top = ;
Stack[++top] = s;
dis[s] = ;
while (top != )
{
int u = Stack[top];
top--;
inq[u] = false;
for (int i = head[u]; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
Stack[++top] = v;
}
}
}
}
} int main()
{
while (scanf("%d%d",&N,&M) != EOF)
{
init();
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
}
Spfa();
printf("%d\n",dis[N]);
}
return ;
}
POJ 2502 Subway
读完提按照他说的来建图即可
我记得当时做的时候感觉超级NM坑。我不知道我自己的建图哪里WA了。反正就换一种别人的写法救过了。我真的不服。。
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const double walkv = * 1000.0 / 60.0;
const double subv = * 1000.0 / 60.0;
const double INF = 1e17;
const double eps = 1e-;
struct Edge
{
int u,v,next;
double w;
bool walk;
}; struct heapnode
{
double val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijkstra
{
int N,M;
bool done[MAXN];
int head[MAXN],tot;
Edge edge[MAXM];
priority_queue<heapnode>q;
double dis[MAXN]; void init(int n,int m)
{
N = n;
M = m;
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u ,int v,double w,bool walk)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
edge[tot].walk = walk;
head[u] = tot++;
} void dijkstra(int s)
{
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[s] = 0.0;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
if (done[u])continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
double tmp;
if (edge[i].walk)
tmp = dis[u] + edge[i].w / walkv ;
else tmp = dis[u] + edge[i].w / subv; if (dis[v] > tmp)
{
dis[v] = tmp;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; struct point
{
double x,y;
int id;
}st,ed,res[MAXN];
double map[MAXN][MAXN];
bool sub[MAXN][MAXN];
int cas,tot; double dis(point &a, point &b)
{
point p;
p.x = a.x - b.x;
p.y = a.y - b.y;
return sqrt(p.x * p.x + p.y * p.y);
} int main()
{
// freopen("sample.txt","r",stdin);
src.init(MAXN,MAXM);
for (int i = ; i < MAXN ; i++)
for (int j = ; j < MAXN ; j++) map[i][j] = -1.0;
for (int i = ; i < ; i++) scanf("%lf%lf",&res[i].x,&res[i].y);
tot = ;
point last,now;
last.x = last.y = -;
while (scanf("%lf%lf", &now.x, &now.y) != EOF)
{
if (!(now.x == - && now.y == -))
{
res[tot++] = now;
if (!(last.x == - && last.y == -))
{
src.add_edge(tot - ,tot - ,dis(res[tot - ],res[tot - ]),false);
src.add_edge(tot - ,tot - ,dis(res[tot - ],res[tot - ]),false);
}
}
last = now;
} for (int i = ; i < tot ; i++)
for (int j = ; j < tot ; j++)
if (map[i][j] == -)
{
map[i][j] = dis(res[i],res[j]);
sub[i][j] = false;
src.add_edge(i,j,map[i][j],true);
src.add_edge(j,i,map[i][j],true);
}
src.dijkstra();
printf("%.0f\n",src.dis[]);
return ;
}
POJ 1062 昂贵的聘礼
读完提见图就行了
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL int
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
int M,N;
struct Edge
{
int u,v,next;
int w;
}; struct heapnode
{
int val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijksta
{
int N,M;
int head[MAXN],tot;
Edge edge[MAXM];
bool done[MAXN];
LL dis[MAXN]; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[s] = ;
// cout << " 122323" << endl;
memset(done,false,sizeof(done));
// cout << "sdsdsdw" << endl;
priority_queue<heapnode>q;
// cout << "!213131" << endl;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// printf("%d %d\n",u,dis[u]);
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; struct node
{
int P,L,X;
int T[MAXN],V[MAXN];
}res[MAXN]; int main()
{
while (scanf("%d%d",&M,&N) != EOF)
{
for (int i = ; i <= N ; i++)
{
scanf("%d%d%d",&res[i].P,&res[i].L,&res[i].X);
for (int j = ; j <= res[i].X ; j++)
scanf("%d%d",&res[i].T[j],&res[i].V[j]);
}
int ret = INF;
for (int i = ; i <= N ; i++)
{
src.init(MAXN,MAXM);
for (int j = ; j <= N ; j++) src.add_edge(,j,res[j].P);
int minlevel = res[i].L;
for (int j = ; j <= N ; j++)
{
if (res[j].L - minlevel > M || minlevel > res[j].L) continue;
else
{
//if (i == 2) cout << j << " " << res[j].L << endl;
for (int k = ; k <= res[j].X ; k++)
{
if (res[res[j].T[k]].L - minlevel > M || minlevel > res[res[j].T[k]].L) continue;
src.add_edge(res[j].T[k],j,res[j].V[k]);
}
}
}
//cout << "1111" << endl;
src.dijkstra();
ret = min(ret,src.dis[]);
}
printf("%d\n",ret);
}
return ;
}
POJ 1847 Tram
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL int
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
int N,M,A,B;
struct Edge
{
int u,v,next;
LL w;
}; struct heapnode
{
LL val;
int u;
bool operator < (const heapnode & rhs) const
{
return val > rhs.val;
}
}; struct Dijksta
{
int N,M;
int head[MAXN],tot;
Edge edge[MAXM];
bool done[MAXN];
LL dis[MAXN];
//priority_queue<heapnode>q; void init(int n,int m)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
M = m;
} void add_edge(int u,int v,LL w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
for (int i = ; i <= N ; i++) dis[i] = INF;
memset(done,false,sizeof(done));
priority_queue<heapnode>q;
dis[s] = ;
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// cout << u << " " << dis[u] << endl;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
}
}src; int main()
{
while (scanf("%d%d%d",&N,&A,&B) != EOF)
{
src.init(MAXN,MAXM);
for (int i = ; i <= N ; i++)
{
int cnt ;
scanf("%d",&cnt);
for (int j = ; j <= cnt ; j++)
{
int x;
scanf("%d",&x);
if (j == ) src.add_edge(i,x,);
else src.add_edge(i,x,);
}
}
src.dijkstra(A);
printf("%d\n",src.dis[B] == INF ? - : src.dis[B]);
}
return ;
}
题意:告诉n个点,每个点都有一个权值,A 到 B的时间等于 (val[b]-val[a])^3 都是单向边,可能存在负环,Q次询问,问从1到询问点的最短路,如果不可达或者点在负环上或者小于3,那么就输出? 否则输出最短路径值
标记负环上的点。
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * MAXN;
const int INF = 0x3f3f3f3f;
queue<int>q;
int N,M;
struct Edge
{
int u,v,next;
int w;
}; struct Spfa
{
int N,M;
bool inq[MAXN];
int dp[MAXN],cnt[MAXN];
int pre[MAXN];
int head[MAXN],tot;
int dis[MAXN];
bool incir[MAXN];
Edge edge[MAXM]; void init(int n,int m)
{
N = n;
M = m;
tot = ;
memset(head,-,sizeof(head));
memset(cnt,,sizeof(cnt));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} void dfs(int pos)
{
incir[pos] = true;
for (int i = head[pos] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (!incir[v])
dfs(v);
}
} void spfa(int s)
{
memset(incir,false,sizeof(incir));
memset(inq,false,sizeof(inq));
for (int i = ; i <= N ; i++) dis[i] = INF;
while (!q.empty()) q.pop();
q.push(s);
dis[s] = ;
cnt[s] = ;
inq[s] = true;
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (incir[v]) continue;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
cnt[v]++;
q.push(v);
if (cnt[v] >= N) dfs(v);
}
}
}
}
}
}src; int res[MAXN]; int main()
{
// freopen("sample.txt","r",stdin);
int T,kase = ;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
for (int i = ; i <= N ; i++) scanf("%d",&res[i]);
scanf("%d",&M);
src.init(N,M);
for (int i = ; i <= M ; i++)
{
int u,v;
scanf("%d%d",&u,&v);
src.add_edge(u,v,(res[v] - res[u]) * (res[v] - res[u]) *
(res[v] - res[u]));
}
src.spfa();
printf("Case %d:\n",kase++);
int q;
scanf("%d",&q);
while (q--)
{
int u;
scanf("%d",&u);
if (src.incir[u] || src.dis[u] < || src.dis[u] >= INF)
printf("?\n");
else printf("%d\n",src.dis[u]);
}
}
return ;
}
HDU 4725 The Shortest Path in Nya Graph
总共3*N个点,1-N个点,N + 1 ---- N + N + N 这几个点分别是拆点的点。
至于为什么要拆点,注意到在一层的点不一定能直接到达。参考数据
3 0 1
1 1 1 ans = -1;
所有层拆点分为前向点 后项点。 见图为点连层前向点,层层之间后连前,具体看代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = MAXN * ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} struct heapnode
{
int val,u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; priority_queue<heapnode>q;
bool done[MAXN];
int dis[MAXN]; void dijkstra(int s)
{
memset(done,false,sizeof(done));
while (!q.empty()) q.pop();
memset(dis,0x3f,sizeof(dis));
dis[s] = ;
heapnode tmp;
tmp.val = dis[s];
tmp.u = s;
q.push(tmp);
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
heapnode tmp;
tmp.val = dis[v];
tmp.u = v;
q.push(tmp);
}
}
}
} int N,M,C;
int main()
{
//freopen("Sample.txt","r",stdin);
int T,kase = ;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&N,&M,&C);
init();
for (int i = ; i <= N ; i++)
{
int x;
scanf("%d",&x);
add_edge(i,N + x,);
add_edge(N + N + x,i,);
}
for (int i = ; i < N ; i++)
{
add_edge(N + i,N + N + i + ,C);
add_edge(N + i + ,N + N + i,C);
}
for (int i = ; i < M ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
// for (int i = 0 ; i < tot ; i++)
// printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
dijkstra();
if (dis[N] == INF) dis[N] = -;
printf("Case #%d: %d\n",kase++,dis[N]); }
return ;
}
HDU 3416 Marriage Match IV
最短路的所有边只能走一次。直接最短路+最大流
这里唯一的问题就是最短路树是什么样子的。有向图和无向图的设置不太一样。前面连通图专题里有无向图的这里有向图的我相关的已经注释区分了
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
struct Edge
{
int u,v,w;
int next;
int id;
bool cut;
}; struct heapnode
{
int val,u;
bool operator < (const heapnode &rhs) const
{
return val > rhs.val;
}
}; priority_queue<heapnode>q; struct Dijkstra
{
int N,M;
int dis[MAXN];
bool done[MAXN];
int head[MAXN],tot;
Edge edge[MAXM]; void init(int n)
{
memset(head,-,sizeof(head));
tot = ;
N = n;
} void add_edge(int u,int v,int w,int id)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].id = id;
edge[tot].next = head[u];
head[u] = tot++;
} void dijkstra(int s)
{
memset(done,false,sizeof(done));
for (int i = ; i <= N ; i++) dis[i] = INF;
dis[s] = ;
while (!q.empty()) q.pop();
q.push((heapnode){dis[s],s});
while (!q.empty())
{
heapnode x = q.top(); q.pop();
int u = x.u;
// cout << u << " " << dis[u] << endl ;
if (done[u]) continue;
done[u] = true;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
q.push((heapnode){dis[v],v});
}
}
}
} }St,Ted; struct Edge2
{
int u,v,next;
int cap,flow;
}edge[MAXM];
int head[MAXN],tot;
int gap[MAXN],dep[MAXN],cur[MAXN]; void init()
{
memset(head,-,sizeof(head));
tot = ;
} void add_edge(int u,int v,int cap,int rcap = )
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].cap = cap;
edge[tot].flow = ;
edge[tot].next = head[u];
head[u] = tot++; edge[tot].u = v;
edge[tot].v = u;
edge[tot].cap = rcap;
edge[tot].flow = ;
edge[tot].next = head[v];
head[v] = tot++;
} int Q[MAXN];
void BFS(int st,int ed)
{
memset(dep,-,sizeof(dep));
memset(gap,,sizeof(gap));
gap[] = ;
int front = ,rear = ;
dep[ed] = ;
Q[rear++] = ed;
while (front < rear)
{
int u = Q[front++];
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dep[v] != -) continue;
Q[rear++] = v;
dep[v] = dep[u] + ;
gap[dep[v]]++;
}
}
} int S[MAXN];
int sap(int st,int ed,int N)
{
BFS(st,ed);
memcpy(cur,head,sizeof(head));
int top = ;
int u = st;
int ans = ;
while (dep[st] < N)
{
if (u == ed)
{
int Min = INF;
int inser;
for (int i = ; i < top ; i++)
{
if (Min > edge[S[i]].cap - edge[S[i]].flow)
{
Min = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
}
for (int i = ; i < top ; i++)
{
edge[S[i]].flow += Min;
edge[S[i] ^ ].flow -=Min;
}
ans += Min;
top = inser;
u = edge[S[top] ^ ].v;
continue;
}
bool flag = false;
int v;
for (int i = cur[u] ; i != - ; i = edge[i].next)
{
v = edge[i].v;
if (edge[i].cap - edge[i].flow && dep[v] + == dep[u])
{
flag = true;
cur[u] = i;
break;
}
}
if(flag)
{
S[top++] = cur[u];
u = v;
continue;
}
int Min = N;
for (int i = head[u] ; i != - ; i = edge[i].next)
{
if (edge[i].cap - edge[i].flow && dep[edge[i].v] < Min)
{
Min = dep[edge[i].v];
cur[u] = i;
}
}
gap[dep[u]]--;
if (!gap[dep[u]]) return ans;
dep[u] = Min + ;
gap[dep[u]]++;
if (u != st) u = edge[S[--top] ^ ].v;
}
return ans;
} int u[MAXM],v[MAXM],w[MAXM];
int A,B,N,M;
int main()
{
// freopen("sample.txt","r",stdin);
int kase;
scanf("%d",&kase);
while (kase--)
{
scanf("%d%d",&N,&M);
St.init(N);
Ted.init(N);
init();
for (int i = ; i < M ; i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
St.add_edge(u[i],v[i],w[i],i + );
//St.add_edge(v[i],u[i],w[i],i + 1);
//Ted.add_edge(u[i],v[i],w[i],i + 1);
Ted.add_edge(v[i],u[i],w[i],i + );
}
scanf("%d%d",&A,&B);
St.dijkstra(A);
/* if (St.dis[B] == INF)
{
puts("0");
continue;
}
*/
Ted.dijkstra(B);
for (int i = ; i < M ; i++)
{
int tu = u[i];
int tv = v[i];
int tw = w[i];
if (tu == tv) continue;
if ((St.dis[tu] + tw == St.dis[tv] && Ted.dis[tv] + tw == Ted.dis[tu])
||(St.dis[tv] + tw == St.dis[tu] && Ted.dis[tu] + tw == Ted.dis[tv]))
{
add_edge(tu,tv,);
}
}
printf("%d\n",sap(A,B,N + )); }
return ;
}
HDU 4370 0 or 1
看bin神题解吧。此题太神了。
这里代码主要记录一下如何求闭环。循环队列等问题
复制的
转换思维的题啊,由一道让人不知如何下手的题,转换为了最短路 基本思路就是把矩阵看做一个图,图中有n个点,1号点出度为1, n号点入度为1,其它点出度和入度相等,路径长度都是非负数,
等价于一条从1号节点到n号节点的路径,故Xij=1表示需要经 过边(i,j),代价为Cij。Xij=0表示不经过边(i,j)。注意到Cij非负 且题目要求总代价最小,因此最优答案的路径一定可以对应一条简单路径。
最终,我们直接读入边权的邻接矩阵,跑一次1到n的最短路即可,记最短路为path。
漏如下的情况B: 从1出发,走一个环(至少经过1个点,即不能 是自环),回到1;从n出发,走一个环(同理),回到n。 也就是1和n点的出度和入度都为1,其它点的出度和入度为0.
由于边权非负,于是两个环对应着两个简单环。
因此我们可以从1出发,找一个最小花费环,记代价为c1, 再从n出发,找一个最小花费环,记代价为c2。 (只需在最短路算法更新权值时多加一条记录即可:if(i==S) cir=min(cir,dis[u]+g[u][i]))
故最终答案为min(path,c1+c2) */ /* 本程序用SPFA来完成最短路。 但是由于要计算从出发点出发的闭环的路径长度。 所以要在普通SPFA的基础上做点变化。
就是把dist[start]设为INF。同时一开始并不是让出发点入队,而是让 出发点能够到达的点入队。
代码:
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int INF = 0x3f3f3f3f;
int cost[MAXN][MAXN];
int dist[MAXN];
int que[MAXN];
bool inq[MAXN]; void spfa(int s,int n)
{
int front = ,rear = ;
for (int v = ; v <= n ; v++)
{
if (v == s)//由于要找start的闭环,所以dist[start]设为INF,且不入队
{
dist[v] = INF;
inq[v] = false;
}
else if(cost[s][v] != INF)
{
dist[v] = cost[s][v];
que[rear++] = v;
inq[v] = true;
}
else//即dist[start][v]==INF情况,对本题没有这种情
{
dist[v] = INF;
inq[v] = false;
}
}
while (front != rear)//注意这个条件是不等,因为是循环队列
{
int u = que[front++];
for (int v = ; v <= n ; v++)
{
if (dist[v] > dist[u] + cost[u][v])
{
dist[v] = dist[u] + cost[u][v];
if (!inq[v])
{
que[rear++] = v;
if (rear >= MAXN) rear = ;
inq[v] = true;
}
}
}
inq[u] = false;
if (front >= MAXN) front = ;
} } int main()
{
int N;
while (scanf("%d",&N) != EOF)
{
memset(cost,0x3f,sizeof(cost));
for (int i = ; i <= N ; i++)
for (int j = ; j <= N ; j++)
scanf("%d",&cost[i][j]);
spfa(,N);
int ans = dist[N];//1到n的最短路
int cmp = dist[];//1的自环长度
spfa(N,N);
cmp += dist[N];//N的自环长度
printf("%d\n",min(ans,cmp));
}
return ;
}
POJ 3169 Layout
查分约束变换一下不等式就行了
对那ML个条件
d[y] - d[x] <= w -> d[x] + w >= d[y]
对那MD个条件
d[y] - d[x] >= w -> d[y] + (-w) >= d[x]
对于一个不等式 d[u] + w >= d[v] 我们可以加边(u, v , w) 因为松弛操作
2份代码
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,ML,MD;
bool inq[MAXN];
int cnt[MAXN];
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int head[MAXN],tot; void init()
{
tot = ;
memset(head,-,sizeof(head));
} void add_edge(int u,int v,int w)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
} queue<int>q;
int dis[MAXN]; bool spfa(int s,int n)
{
memset(inq,false,sizeof(inq));
memset(cnt,,sizeof(cnt));
memset(dis,0x3f,sizeof(dis));
while(!q.empty()) q.pop();
q.push(s);
dis[s] = ;
inq[s] = true;
cnt[s] = ;
while (!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
//printf("%d %d\n",u,dis[u]);
for (int i = head[u] ; i != - ; i = edge[i].next)
{
int v = edge[i].v;
if (dis[v] > dis[u] + edge[i].w)
{
dis[v] = dis[u] + edge[i].w;
if (!inq[v])
{
inq[v] = true;
q.push(v);
cnt[v]++;
}
if(cnt[v] >= n) return true;
}
}
}
return false;
} int main()
{
while (scanf("%d%d%d",&N,&ML,&MD) != EOF)
{
init();
for (int i = ; i < ML ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(u > v) swap(u,v);
add_edge(u,v,w);
}
for (int i = ; i < MD ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if (u < v) swap(u,v);
add_edge(u,v,-w);
}
// for (int i = 0 ; i < tot ; i++) printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
if (spfa(,N)) puts("-1");
else if (dis[N] >= INF) puts("-2");
else printf("%d\n",dis[N]);
}
return ;
}
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == ? b : gcd(b, a % b);}
const int MAXN = ;
const int MAXM = ;
const int INF = 0x3f3f3f3f;
int N,ML,MD;
int dis[MAXN];
struct Edge
{
int u,v,w;
int next;
}edge[MAXM];
int tot; bool bellman_ford(int s,int n)
{
memset(dis,0x3f,sizeof(dis));
dis[s] = ;
for (int i = ; i <= n - ; i++)
{
for (int j = ; j < tot ; j++)
{
int u = edge[j].u;
int v = edge[j].v;
if (dis[v] > dis[u] + edge[j].w)
{
dis[v] = dis[u] + edge[j].w;
}
// printf("%d %d %d %d\n",u,v,dis[u],edge[j].w);
}
}
for (int j = ; j < tot ; j++)
{
if (dis[edge[j].v] > dis[edge[j].u] + edge[j].w)
return true;
}
return false;
} int main()
{
while (scanf("%d%d%d",&N,&ML,&MD) != EOF)
{
tot = ;
for (int i = ; i < ML ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(u > v) swap(u,v);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
tot++;
}
for (int i = ; i < MD ; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if (u < v) swap(u,v);
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = -w;
tot++;
}
//for (int i = 0 ; i < tot ; i++) printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
if (bellman_ford(,N)) puts("-1");
else if (dis[N] >= INF) puts("-2");
else printf("%d\n",dis[N]);
}
return ;
}
kuangbin带你飞 最短路 题解的更多相关文章
- 专题训练——[kuangbin带你飞]最短路练习
最短路练习 0. Til the Cows Come Home POJ - 2387 完美的模板题 //#include<Windows.h> #include<iostream& ...
- Kuangbin 带你飞 数位DP题解
以前一直不知道该咋搞这个比较好. 感觉推起来那个数字好麻烦.后来有一种比较好的写法就是直接的DFS写法.相应的ismax表示当前位是否有限制. 数位DP也是有一种类似模版的东西,不过需要好好理解.与其 ...
- kuangbin带你飞 后缀数组 题解
2份模板 DC3 . 空间复杂度O3N 时间复杂度On #define F(x) ((x) / 3 + ((x) % 3 == 1 ? 0 : tb)) #define G(x) ((x) < ...
- Dancing Links [Kuangbin带你飞] 模版及题解
学习资料: http://www.cnblogs.com/grenet/p/3145800.html http://blog.csdn.net/mu399/article/details/762786 ...
- Tarjan 联通图 Kuangbin 带你飞 联通图题目及部分联通图题目
Tarjan算法就不说了 想学看这 https://www.byvoid.com/blog/scc-tarjan/ https://www.byvoid.com/blog/biconnect/ 下面是 ...
- 「kuangbin带你飞」专题十七 AC自动机
layout: post title: 「kuangbin带你飞」专题十七 AC自动机 author: "luowentaoaa" catalog: true tags: - ku ...
- KUANGBIN带你飞
KUANGBIN带你飞 全专题整理 https://www.cnblogs.com/slzk/articles/7402292.html 专题一 简单搜索 POJ 1321 棋盘问题 //201 ...
- 「kuangbin带你飞」专题二十 斜率DP
layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...
- 「kuangbin带你飞」专题二十二 区间DP
layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...
随机推荐
- SQL 基础笔记(三):约束
个人笔记不保证正确. 数据类型是限制我们可以在表里存储什么数据的一种方法.不过,对于许多应用来说, 这种限制实在是太粗糙了.比如,一个包含产品价格的字段应该只接受正数. 但是没有哪种标准数据类型只接受 ...
- HDU 4565 So Easy!(数学+矩阵快速幂)(2013 ACM-ICPC长沙赛区全国邀请赛)
Problem Description A sequence Sn is defined as:Where a, b, n, m are positive integers.┌x┐is the cei ...
- vim使用注意事项
vim使用注意事项 1. 中文编码的问题 中文编码有很多,如果文件与vim的终端界面使用的编码不同,那么在vim显示的文件内容将会是一堆乱码. 2. 语系编码转换 命令iconv可以将语系编码进行转换 ...
- rcnn spp_net
在http://www.cnblogs.com/jianyingzhou/p/4086578.html中 提到 rcnn开创性工作,但是计算时间太长,重复计算太大. spp_net将重复计算避免了 我 ...
- Linux SPI总线和设备驱动架构之二:SPI通用接口层
通过上一篇文章的介绍,我们知道,SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了 ...
- 【Python】Python内置函数dir详解
1.命令介绍 最近学习并使用了一个python的内置函数dir,首先help一下: 复制代码代码如下: >>> help(dir)Help on built-in function ...
- exec族
在之前我们已经知道用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序.当进程调用一种exec函数时,该进程的用户空间代码和 ...
- Top K 算法详解
http://xingyunbaijunwei.blog.163.com/blog/static/7653806720111149318357/ 问题描述 百度面试题: ...
- 完全删除SQL server 2008
一.在控制面板卸载程序 二.点击删除 遇到这种情况则重新启动计算机,之后依次按步骤进行即可. 三.卸载一些相关组件,方法与之类似 四.删除磁盘里的默认文件(一般数据库默认安装在C盘) 路径:" ...
- 洛谷 P1251 餐巾计划问题
题目链接 最小费用最大流. 每天拆成两个点,早上和晚上: 晚上可以获得\(r_i\)条脏毛巾,从源点连一条容量为\(r_i\),费用为0的边. 早上要供应\(r_i\)条毛巾,连向汇点一条容量为\(r ...