计算机模拟虫洞,「NOIP模拟赛」虫洞

「题目描述」

N个虫洞,M条单向跃迁路径。从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间。虫洞有白洞和黑洞之分。设一条跃迁路径两端的虫洞质量差为delta。

从白洞跃迁到黑洞,消耗的燃料值减少delta,若该条路径消耗的燃料值变为负数的话,取为0。

从黑洞跃迁到白洞,消耗的燃料值增加delta。

路径两端均为黑洞或白洞,消耗的燃料值不变化。

作为压轴题,自然不会是如此简单的最短路问题,所以每过1单位时间黑洞变为白洞,白洞变为黑洞。在飞行过程中,可以选择在一个虫洞停留1个单位时间,如果当前为白洞,则不消耗燃料,否则消耗s[i]的燃料。现在请你求出从虫洞1到N最少的燃料消耗,保证一定存在1到N的路线。

「输入格式」

第1行:2个正整数N,M

第2行:N个整数,第i个为0表示虫洞i开始时为白洞,1表示黑洞。

第3行:N个整数,第i个数表示虫洞i的质量w[i]。

第4行:N个整数,第i个数表示在虫洞i停留消耗的燃料s[i]。

第5..M+4行:每行3个整数,u,v,k,表示在没有影响的情况下,从虫洞u到虫洞v需要消耗燃料k。

「输出格式」

一个整数,表示最少的燃料消耗。

「样例输入」

4 5

1 0 1 0

10 10 100 10

5 20 15 10

1 2 30

2 3 40

1 3 20

1 4 200

3 4 200

「样例输出」

130

「数据范围」

对于30%的数据: 1<=N<=100,1<=M<=500

对于60%的数据: 1<=N<=1000,1<=M<=5000

对于100%的数据: 1<=N<=5000,1<=M<=30000

其中20%的数据为1<=N<=3000的链

1<=u,v<=N, 1<=k,w[i],s[i]<=200

「样例说明」

按照1->3->4的路线。

题解

首先每个点拆成黑白点

本来一个黑到一个白连边v+delta

但是因为每秒会变色,所以是一个黑到一个黑连边v+delta

条件是俩点的初始颜色不同

其余的同理

然后最短路。。。

一开始spfa写错只有80分好伤心。。

C++

#include

#include

#include

#include

#define ll long long

using namespace std;

inline int read()

{

char ch=getchar();

int f=1,x=0;

while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}

while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}

return x*f;

}

int n,m,cnt;

int q[10005];ll d[10005];

bool mp[10005],inq[10005];

int w[10005],s[10005];

int h[10005],head[10005];

struct data{int to,next,v;}ed[100005],e[200005];

void ins(int u,int v,int w)

{ed[++cnt].to=v;ed[cnt].v=w;ed[cnt].next=h[u];h[u]=cnt;}

void insert(int u,int v,int w)

{e[++cnt].to=v;e[cnt].v=w;e[cnt].next=head[u];head[u]=cnt;}

void build(int x)

{

insert(x,x+n,s[x]);

insert(x+n,x,0);

for(int i=h[x];i;i=ed[i].next)

{

int de=abs(w[x]-w[ed[i].to]);

if(mp[x]!=mp[ed[i].to])

{

insert(x,ed[i].to,ed[i].v+de);

insert(x+n,ed[i].to+n,max(0,ed[i].v-de));

}

else

{

insert(x,ed[i].to+n,ed[i].v);

insert(x+n,ed[i].to,ed[i].v);

}

}

}

void spfa()

{

int t=0,w=1;

memset(d,127,sizeof(d));

if(mp[1]){q[0]=1;d[1]=0;inq[1]=1;}

else {q[0]=n+1;d[n+1]=0;inq[n+1]=1;}

while(t!=w)

{

int now=q[t];t++;if(t==10001)t=0;

for(int i=head[now];i;i=e[i].next)

{

if(e[i].v+d[now]

{

d[e[i].to]=d[now]+e[i].v;

if(!inq[e[i].to])

{

inq[e[i].to]=1;

q[w++]=e[i].to;

if(w==10001)w=0;

}

}

}

inq[now]=0;

}

printf("%I64d",min(d[n],d[n+n]));

}

int main()

{

//freopen("holes.in","r",stdin);

//freopen("holes.out","w",stdout);

scanf("%d%d",&n,&m);

for(int i=1;i<=n;i++)

mp[i]=read();

for(int i=1;i<=n;i++)

w[i]=read();

for(int i=1;i<=n;i++)

s[i]=read();

for(int i=1;i<=m;i++)

{

int u=read(),v=read(),w=read();

ins(u,v,w);

}

cnt=0;

for(int i=1;i<=n;i++)

build(i);

spfa();

return 0;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

#include

#include

#include

#include

#define ll long long

usingnamespacestd;

inlineintread()

{

charch=getchar();

intf=1,x=0;

while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}

while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}

returnx*f;

}

intn,m,cnt;

intq[10005];lld[10005];

boolmp[10005],inq[10005];

intw[10005],s[10005];

inth[10005],head[10005];

structdata{intto,next,v;}ed[100005],e[200005];

voidins(intu,intv,intw)

{ed[++cnt].to=v;ed[cnt].v=w;ed[cnt].next=h[u];h[u]=cnt;}

voidinsert(intu,intv,intw)

{e[++cnt].to=v;e[cnt].v=w;e[cnt].next=head[u];head[u]=cnt;}

voidbuild(intx)

{

insert(x,x+n,s[x]);

insert(x+n,x,0);

for(inti=h[x];i;i=ed[i].next)

{

intde=abs(w[x]-w[ed[i].to]);

if(mp[x]!=mp[ed[i].to])

{

insert(x,ed[i].to,ed[i].v+de);

insert(x+n,ed[i].to+n,max(0,ed[i].v-de));

}

else

{

insert(x,ed[i].to+n,ed[i].v);

insert(x+n,ed[i].to,ed[i].v);

}

}

}

voidspfa()

{

intt=0,w=1;

memset(d,127,sizeof(d));

if(mp[1]){q[0]=1;d[1]=0;inq[1]=1;}

else{q[0]=n+1;d[n+1]=0;inq[n+1]=1;}

while(t!=w)

{

intnow=q[t];t++;if(t==10001)t=0;

for(inti=head[now];i;i=e[i].next)

{

if(e[i].v+d[now]

{

d[e[i].to]=d[now]+e[i].v;

if(!inq[e[i].to])

{

inq[e[i].to]=1;

q[w++]=e[i].to;

if(w==10001)w=0;

}

}

}

inq[now]=0;

}

printf("%I64d",min(d[n],d[n+n]));

}

intmain()

{

//freopen("holes.in","r",stdin);

//freopen("holes.out","w",stdout);

scanf("%d%d",&n,&m);

for(inti=1;i<=n;i++)

mp[i]=read();

for(inti=1;i<=n;i++)

w[i]=read();

for(inti=1;i<=n;i++)

s[i]=read();

for(inti=1;i<=m;i++)

{

intu=read(),v=read(),w=read();

ins(u,v,w);

}

cnt=0;

for(inti=1;i<=n;i++)

build(i);

spfa();

return0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值