POJ 1062
题意:中文题,略;
做法:虚拟一个起点为0节点(到其他物品的权值是原价),每个物品看成一个节点,酋长的允诺也看作一个物品, 如果一个物品加上金币可以交换另一个物品,则这两个节点之间有边,权值为优惠完后的值,求第0个节点到第1个节点的最短路
注意:因为有等级限制,所以枚举所能选的等级范围[l , r] , 多次最短路即可
#include <iostream>
#include <queue>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
const int inf=0x3f3f3f;
int map[110][110];
int rate[110];
int n,m;
bool vis[110];
int dis[110];
int spfa(int l,int r)
{
for(int i=0;i<=n;++i)
{
dis[i]=inf; vis[i]=0;
}
dis[0]=0; vis[0]=1;
queue<int>que;
que.push(0);
while(!que.empty())
{
int u=que.front() ;que.pop(); vis[u]=0;
for(int i=1;i<=n;++i)
{
if(rate[i]<l||rate[i]>r) continue;
if(dis[i]>dis[u]+map[u][i])
{
dis[i]=dis[u]+map[u][i];
if(!vis[i])
{
vis[i]=1; que.push(i);
}
}
}
}
return dis[1];
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=0;i<=n;++i)
{
for(int j=0;j<=n;++j)
{
map[i][j]=inf;
if(i==j) map[i][j]=0;
}
}
rate[0]=inf;
for(int i=1;i<=n;++i)
{
int p,l,x;
scanf("%d%d%d",&p,&l,&x);
rate[i]=l;
map[0][i]=p;
for(int j=1;j<=x;++j)
{
int t,v;
scanf("%d%d",&t,&v);
map[t][i]=max(0,min(v,map[t][i]));
}
}
int ans=inf;
for(int i=0;i<=m;++i)
{
int l=rate[1]+i-m;
int r=rate[1]+i;
ans=min(ans,spfa(l,r));
}
printf("%d\n",ans);
return 0;
}
POJ 1847
题意:火车行驶过程有n条岔路(每次只能走一条),默认是第一条路..如果需要改路的话需要操作一次,问从a到b最少需要操作多少次n个点 a,b是起点和终点,然后n行,第i行有k个点,代表第i个点可以走到这k个点,初始默认方向是第一个点的方向...其他的改道一次需要操作一次。
做法:最短路,只需要把建边的时候,默认的方向为免费边,非默认方向权值为1,不能到达为inf
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
using namespace std;
int n,a,b;
int map[110][110];
const int inf=0x3f3f3f;
bool vis[110];
int dis[110];
void spfa()
{
for(int i=1;i<=n;++i)
{
vis[i]=0; dis[i]=inf;
}
vis[a]=1; dis[a]=0;
queue<int>que;
que.push(a);
while(!que.empty())
{
int u=que.front() ; que.pop(); vis[u]=0;
for(int i=1;i<=n;++i)
{
if(dis[i]>dis[u]+map[u][i])
{
dis[i]=dis[u]+map[u][i];
if(!vis[i])
{
vis[i]=1; que.push(i);
}
}
}
}
if(dis[b]==inf) dis[b]=-1;
printf("%d\n",dis[b]);
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
map[i][j]=inf;
if(i==j) map[i][j]=0;
}
}
for(int i=1;i<=n;++i)
{
int m;
scanf("%d",&m);
int flag=0;
for(int j=1;j<=m;++j)
{
int to;
scanf("%d",&to);
map[i][to]=flag;
if(flag==0) flag=1;
}
}
spfa();
return 0;
}
LIGHT OJ 1074
题意:有n个城市,每一个城市有一个拥挤度ai,从一个城市I到另一个城市J的时间为:(aJ-aI)^3,存在负环。问从第一个城市到达第k个城市所花的时间,如果不能到达,或者时间小于3输出?否则输出所花的时间
思路:用spfa找出的所有的负环,把所有负环能到的点标记一下(这里用dfs,递归标记把负环里的点都标记了)。
思路:用spfa找出的所有的负环,把所有负环能到的点标记一下(这里用dfs,递归标记把负环里的点都标记了)。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,k;;
int val[320];
int du[320];
int dis[320];
bool vis[320];
int cic[320];
int head[320];
int cnt=0;
struct node
{
int to,next,w;
}edge[200*410];
void add(int u,int v,int w)
{
edge[cnt].to=v; edge[cnt].w=w;
edge[cnt].next=head[u]; head[u]=cnt++;
}
void dfs(int x)
{
cic[x]=1;
for(int i=head[x];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(!cic[v]) dfs(v);
}
}
void spfa(int x)
{
queue<int> que;
while(que.size()) que.pop();
memset(vis,0,sizeof(vis));
memset(du,0,sizeof(du));
memset(cic,0,sizeof(cic));
memset(dis,inf,sizeof(dis));
dis[x]=0; vis[x]=1; du[x]++; que.push(x);
while(!que.empty())
{
int u=que.front() ;que.pop(); vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to, w=edge[i].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(!vis[v]&&!cic[v])
{
vis[v]=1; que.push(v); du[v]++;
}
if(du[v]>=n&&!cic[v]) dfs(v);
}
}
}
}
int main()
{
int T;
cin>>T;
int kase=1;
while(T--)
{
memset(head,-1,sizeof(head)); cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&val[i]);
}
scanf("%d",&m);
while(m--)
{
int c1,c2;
scanf("%d%d",&c1,&c2); int temp=val[c2]-val[c1];
add(c1,c2,temp*temp*temp);
}
spfa(1);
scanf("%d",&k);
printf("Case %d:\n",kase++);
while(k--)
{
int aim;
scanf("%d",&aim);
if(cic[aim]||dis[aim]<3||dis[aim]==inf) printf("?\n");
else printf("%d\n",dis[aim]);
}
}
return 0;
}
HDU 4725
题意:n个点,m条边,以及相邻层之间移动的代价c,给出每个点所在的层数,以及m条边,每条边有u,v,c,表示从节点u到v(无向),并且移动的代价 c ,问说从 1 到 n 的代价最小是多少。
做法:拆点,1-N代表点 N+1-2*N 代表层数, 建图一定要小心,自己建图的时候忘记判断两层是否有点,wa了好几发。
需要建的边, 该层内的点 到 代表该层的点 权值为0
代表不同层的点之间 权值为c (记得判断层内是否有点)
点 到 代表非本层的点(只用取左右两层即可) 权值为c (记得判断1[无左]和n层[无右])
代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
typedef long long ll;
using namespace std;
const long long inf=0x3f3f3f3f;
const int maxn=200000+10;
const int mam=800000+10;
int head[maxn];
int lay[maxn];
bool vislay[maxn];
int cnt=0;
int n,m;
int c;
struct node
{
int next,to;
int w;
}edge[maxn*50];
void add(int u,int v,ll w)
{
edge[cnt].next=head[u]; edge[cnt].to=v;
edge[cnt].w=w; head[u]=cnt++;
}
bool vis[maxn];
int dis[maxn];
struct enode
{
int pos,step;
bool friend operator < (const enode a, const enode b)
{
return a.step>b.step;
}
};
void dij()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=2*n;++i) dis[i]=inf;
dis[1]=0;
struct enode u,v;
u.step=0;u.pos=1;
priority_queue<enode> que;
que.push(u);
while(!que.empty())
{
u=que.top() ;que.pop();
if(vis[u.pos]) continue;
vis[u.pos]=1;
int st=u.pos;
for(int i=head[st];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
int w=edge[i].w;
if(dis[to]>dis[st]+w)
{
dis[to]=dis[st]+w;
if(!vis[to])
{
v.pos=to; v.step=dis[to];
que.push(v);
}
}
}
}
if(dis[n]==inf||n==0) dis[n]=-1;
printf("%d\n",dis[n]);
}
int main()
{
int T;
scanf("%d",&T);
int kcase=1;
while(T--)
{
memset(head,-1,sizeof(head)); cnt=0;
memset(vislay,0,sizeof(vislay));
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=n;++i)
{
int temp;
scanf("%d",&temp);
lay[i]=temp; vislay[temp]=1;
}
for(int i=1;i<n;++i)
{
if(vislay[i]&&vislay[i+1])
{
add(i+n,i+1+n,c); add(i+n+1,i+n,c);
}
}
for(int i=1;i<=n;++i)
{
add(n+lay[i],i,0);
if(lay[i]>1)
{
add(i,n+lay[i]-1,c); add(n+lay[i]-1,i,c);
}
if(lay[i]<n)
{
add(i,n+lay[i]+1,c); add(n+lay[i]+1,i,c);
}
}
for(int i=1;i<=m;++i)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
printf("Case #%d: ",kcase++);
dij();
}
return 0;
}