最短路建图
BZOJ-4152
分析
请%大佬博客
注意:本题卡spfa;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <bitset>
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
#define lson (x << 1)
#define rson (x << 1 | 1)
using namespace std;
template<typename xxx>inline void read(xxx &x) {
x = 0;int f = 1;char c = getchar();
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') f = -1,c = getchar();
for(;isdigit(c);c = getchar()) x = (x << 3) + (x << 1) + (c ^ '0');
x *= f;
}
template<typename xxx>inline void print(xxx x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 200010;
const int mod = 1e9 + 7;
const int inf = 0x7f7f7f7f;
struct node {
int xi,yi,id;
}g[maxn];
inline bool gmpx(node a,node b) {
if(a.xi == b.xi) return a.yi < b.yi;
else return a.xi < b.xi;
}
inline bool gmpy(node a,node b) {
if(a.yi == b.yi) return a.xi < b.xi;
else return a.yi < b.yi;
}
struct edge {
int to,last;
ll val;
}e[maxn<<2];
int head[maxn<<2],tot;
inline void add(int from,int to,ll val) {
++tot;
e[tot].to = to;
e[tot].val = val;
e[tot].last = head[from];
head[from] = tot;
}
int n;
ll dis[maxn];
int vis[maxn];
queue<int>q;
inline void spfa() {
for(rint i = 0;i <= n; ++i) dis[i] = 1e16;
q.push(1);dis[1] = 0;
while(q.size()) {
int x = q.front();q.pop();vis[x] = 0;
for(rint i = head[x];i;i = e[i].last) {
if(dis[e[i].to] > dis[x] + e[i].val) {
dis[e[i].to] = dis[x] + e[i].val;
if(!vis[e[i].to]) {
vis[e[i].to] = 1;
q.push(e[i].to);
}
}
}
}
return ;
}
int main() {
read(n);
for(rint i = 1;i <= n; ++i) {
read(g[i].xi);
read(g[i].yi);
g[i].id = i;
}
stable_sort(g + 1,g + n + 1,gmpx);
for(rint i = 1;i < n; ++i) {
int disx = g[i + 1].xi - g[i].xi;
int disy = g[i + 1].yi - g[i].yi;
if(disx < 0) disx = -disx;
if(disy < 0) disy = -disy;
if(disx <= disy) {
add(g[i].id,g[i + 1].id,disx);
add(g[i + 1].id,g[i].id,disx);
// cout<<i<<" "<<i + 1<<" "<<disx<<endl;
}
}
stable_sort(g + 1,g + n + 1,gmpy);
for(rint i = 1;i < n; ++i) {
int disx = g[i + 1].xi - g[i].xi;
int disy = g[i + 1].yi - g[i].yi;
if(disx < 0) disx = -disx;
if(disy < 0) disy = -disy;
if(disx >= disy) {
add(g[i].id,g[i + 1].id,disy);
add(g[i + 1].id,g[i].id,disy);
// cout<<i<<" "<<i + 1<<" "<<disy<<endl;
}
}
spfa();
print(dis[n]);
}
/*
*/
HDU-4725
分析
每层增设两个虚点,层内点只能通过一个走向相邻层,相邻层点只能走另一点到该层。两点与本层的点连权为0的边,向外连长为c的边。本题理论上有相邻层不连通情况,但是数据没有...
注意:数组要开大,否则会wa一上午
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <bitset>
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
#define lson (x << 1)
#define rson (x << 1 | 1)
using namespace std;
template<typename xxx>inline void read(xxx &x) {
x = 0;int f = 1;char c = getchar();
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') f = -1,c = getchar();
for(;isdigit(c);c = getchar()) x = (x << 3) + (x << 1) + (c ^ '0');
x *= f;
}
template<typename xxx>inline void print(xxx x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 1000010;
const int mod = 1e9 + 7;
const int inf = 0x7f7f7f7f;
struct edge {
int to,last;
int val;
}e[maxn];
int head[maxn],tot;
inline void add(int from,int to,int val) {
++tot;
e[tot].to = to;
e[tot].val = val;
e[tot].last = head[from];
head[from] = tot;
}
int n,m,C;
int dis[maxn];
int vis[maxn];
int num[maxn/10];
priority_queue< pair<ll,int> >q;
inline void spfa() {
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
q.push(make_pair(0,1));dis[1] = 0;
while(q.size()) {
int x = q.top().second;q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(rint i = head[x];i;i = e[i].last) {
if(vis[e[i].to]) continue;
if(dis[e[i].to] > dis[x] + e[i].val) {
dis[e[i].to] = dis[x] + e[i].val;
q.push(make_pair(-dis[e[i].to],e[i].to));
}
}
}
return ;
}
int main() {
int t;read(t);
for(rint o = 1;o <= t; ++o) {
tot = 0;
memset(num,0,sizeof(num));
memset(head,0,sizeof(head));
read(n);read(m);read(C);
for(rint i = 1;i <= n; ++i) {
int tp ;
read(tp);
add(i,n + tp,0);
add((n << 1) + tp,i,0);
++num[tp];
}
for(rint i = 1;i <= m; ++i) {
int a,b,c;
read(a);read(b);read(c);
add(a,b,c);
add(b,a,c);
}
for(rint i = 2;i <= n; ++i) {
if(num[i - 1] && num[i]) {
add(n + i,(n << 1) + i - 1,C);
add(n + i - 1,(n << 1) + i,C);
}
}
spfa();
printf("Case #%d: ",o);
if(dis[n] == 0x7f7f7f7f) print(-1);
else print(dis[n]);
putchar('\n');
}
}
/*
*/
[BZOJ-2259]
分析
本题亦可以dp做
我们考虑把序列的每个下标看做一种状态,dis[i]表示把i之前的点恰好完全处理所需的最小花费,明显dis[n + 1]是答案。考虑暴力建边,如果i + a[i] + 1 <= n + 1(即i + a[i] <= n),那么由题目可知状态i到状态i + a[i]花费为0,否则i到i + a[i]的花费为i + a[i] - n(因为ai要减去这么多)。其他的边暴力建会导致\(O(n^2)\),我们则可以考虑让每个点与它前后向邻点建权为1的边,每个点刚好有加或减两种选择。特殊:1前面没有点不需建向前的边,1后面不加是因为走向后建的边上一个ai会变大,第一次做贡献时上一个ai是a1,而a1变大只能走向1+a1+2,不一定是2,而走到其他点时上一个ai变化不受限(话说有没有大佬能给这个题一个详细的解释暴打我的xbb啊......)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <bitset>
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
#define lson (x << 1)
#define rson (x << 1 | 1)
using namespace std;
template<typename xxx>inline void read(xxx &x) {
x = 0;int f = 1;char c = getchar();
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') f = -1,c = getchar();
for(;isdigit(c);c = getchar()) x = (x << 3) + (x << 1) + (c ^ '0');
x *= f;
}
template<typename xxx>inline void print(xxx x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 1000010;
const int mod = 1e9 + 7;
const int inf = 0x7f7f7f7f;
struct edge{
int to,last,val;
}e[maxn<<2];
int head[maxn],tot;
inline void add(int from,int to,int val) {
++tot;
e[tot].to = to;
e[tot].val = val;
e[tot].last = head[from];
head[from] = tot;
}
int n;
struct node{
int dis,pos;
bool operator < (const node & x) const{
return x.dis < dis;
}
};
priority_queue<node>q;
int dis[maxn],vis[maxn];
inline void dj() {
for(rint i = 0;i <= n + 1; ++i) {
dis[i] = mod;
vis[i] = 0;
}
q.push((node){0,1});dis[1] = 0;
while(q.size()) {
node x = q.top();q.pop();
if(vis[x.pos]) continue;
vis[x.pos] = 1;
for(rint i = head[x.pos];i;i = e[i].last) {
if(vis[e[i].to]) continue;
if(dis[e[i].to] > dis[x.pos] + e[i].val) {
dis[e[i].to] = dis[x.pos] + e[i].val;
q.push((node){dis[e[i].to],e[i].to});
}
}
}
}
int main() {
read(n);
for(rint i = 1;i <= n; ++i) {
int a;read(a);
if(i > 1) add(i,i - 1,1),add(i,i + 1,1);
if(i + a <= n) add(i,i + a + 1,0);
else add(i,n + 1,i + a - n);
}
dj();
print(dis[n + 1]);
}
/*
*/