Tyvj P2079(Spfa)

P2079 - 防御机制

From tangjz    Normal (OI)
总时限:10s    内存限制:128MB    代码长度限制:64KB

背景 Background

NOIp2012考后欢乐赛第三题

描述 Description

  服务器的新防御系统快要建好了,但是当正在数据库升级的时候,突然有黑客入侵机房网络,但是就在那时,插网线的房间钥匙丢了。所以Admin开始做防御机房的工作。
  不过,由于访问某台电脑可经过其他电脑加速,但是不能访问途经电脑,而且单位时间内一台电脑只能发出一条指令,指令不含嵌套指令,Admin只能一台一台的建立防御,幸好如此,黑客也是一台一台入侵,不过二人都会选择最优方案进行操作。所以Admin在主控端(教师端)不停的巡察各台电脑的同时,要求你在简短的时间内帮Admin计算一下哪些电脑将必然被入侵成功,以便于Admin及时做出额外的保护措施,如果所有可能被入侵的电脑都能被保护,那么请计算出将所有连接在主控端上的电脑做好防御所需的总时间。
  注意:只有黑客的入侵时间短于Admin的防御时间,黑客才能成功入侵。

输入格式 InputFormat

第一行为两个正整数N,M,表示有N台电脑,M条网线。(黑客近似地看为第N台电脑,在机房外)
第二行为N-2个正整数,表示每台电脑的访问时间t。
第三行到第 M+2 行,每行三个整数u,v,w,表示电脑u和v之间有一条网线,使用该网线互相到达对方电脑需要w个单位时间。

输出格式 OutputFormat

输出共两行。
如果有可能会防御失败的电脑,第一行输出"No",第二行升序输出这些电脑的编号(空格隔开)。
否则第一行输出"Yes",第二行输出将所有连接在主服务器上的电脑做好防御所需的总时间。

样例输入 SampleInput [复制数据]

[Sample 1]
4 6
1 2
1 2 10
1 3 5
1 4 1
2 3 4
2 4 1
3 4 10

[Sample 2]
5 7
1 1 1
1 2 70
1 3 70
1 4 70
1 5 70
2 5 70
3 5 70
4 5 70

样例输出 SampleOutput [复制数据]

[Sample 1]
No
2

[Sample 2]
Yes
213

数据范围和注释 Hint

样例解释:
第一组:由于1->2:2,4->2:1,所以2号电脑会被入侵成功
第二组:1到2,3,4点的时间均为71,5到2,3,4点的时间均为71,防御成功

对于20% 的数据,1 <=  N  <= 1000 ,1 <=  M  <= 2000
对于60% 的数据,1 <=  N  <= 5000 ,1 <=  M  <= 100000
对于100%的数据,1 <=  N  <= 10000,1 <=  M  <= 200000
对于100%的数据,1 <= t,w <= 10000,1 <= u,v <= N
提示:由于学生贪玩,有可能某个电脑没有连接主机,却接入网络;当然也有部分同学上课被禁网了。

时间限制 TimeLimitation

1s

来源 Source

tjz

这题就是Spfa.


Program defence;
const
   maxn=90000;
   maxm=500000;
   inf=2139062143;
type
   dis_arr=record
              s:longint;
              d:array[1..maxn] of longint;
           end;
var
   n,m,i,j:longint;
   w:array[1..maxn] of longint;
   head,edge,next,weight:array[1..maxm] of longint;
   size:longint;
   d1,d2:dis_arr;
   queue:array[1..6000000] of longint;

Procedure addedge(u,v,w:longint);
begin
   inc(size);
   edge[size]:=v;
   weight[size]:=w;
   next[size]:=head[u];
   head[u]:=size;
end;
Procedure addedge_main;
var
   u,v,w:longint;
begin
   read(u,v,w);
   addedge(u,v,w);addedge(v,u,w);
end;
Procedure spfa(var d:dis_arr);
var
   i,j,now,p:longint;
begin
   i:=1;j:=1;queue[1]:=d.s;
   fillchar(d.d,sizeof(d.d),127);d.d[d.s]:=0;
   while (i<=j) do
   begin
      now:=queue[i];
      p:=head[now];
      while (p<>0) do
      begin
         if (d.d[now]+weight[p]<d.d[edge[p]]) then
         begin
            inc(j);
            queue[j]:=edge[p];
            d.d[edge[p]]:=d.d[now]+weight[p];
         end;
         p:=next[p];
      end;
      inc(i);
   end;
end;
Procedure print;
var
   i,j:longint;
   ans:int64;
   flag:boolean;
begin
   flag:=false;    ans:=0;
   for i:=2 to n-1 do
   begin
      if d1.d[i]<>inf then ans:=ans+int64(w[i]+d1.d[i]);
      if (d1.d[i]>d2.d[i]) then
      begin
         if not(flag) then begin flag:=true; writeln('No'); end
         else write(' ');
         write(i);
      end;
   end;
   if not(flag) then
   begin
      writeln('Yes');
      writeln(ans);
   end
   else writeln;
end;
begin
//   assign(input,'defence.in');
//   reset(input);
   fillchar(head,sizeof(head),0);
   fillchar(edge,sizeof(edge),0);
   fillchar(next,sizeof(next),0);
   size:=0;
   read(n,m); d1.s:=1;d2.s:=n;
   for i:=2 to n-1 do read(w[i]);
   for i:=1 to m do
   begin
      addedge_main;
   end;
   spfa(d1);spfa(d2);
   print;
end.

POJ 2355(区间最大值-zkw线段树优化Dp方程)

Language:
Railway tickets
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 2379   Accepted: 823

Description

从1号车站Ekaterinburg到n号车站Sverdlovsk有一条铁路。 


订票时票价如下

2车站间的距离 -X

价格t

0<X<=L1

C1

L1<X<=L2

C2

L2<X<=L3

C3



由于总总原因,距离超过L3的车票不能定。
现在你打算从s号车站乘铁路到t号车站,求最小费用。

Input

第一行有6个数 L1, L2, L3, C1, C2, C3 (1 <= L1 < L2 < L3 <= 10^9, 1 <= C1 < C2 < C3 <= 10^9)
第二行为车站数N (2 <= N <= 10000)
第三行为s和t,表示起点和终点.
接下来n-1行,表示从第1好车站到第i(1<i<=n)号车站的距离(保证是升序).

Output

仅一行,为最小费用(<10^9)

Sample Input

3 6 8 20 30 40
7
2 6
3
7
8
13
15
23

Sample Output

70

Source

这题就是Dp

显然F[i]=F[j]+c[k](j<i,a[j]-a[i]<=l[k],1<=k<=3) F[i]表示从起点s到车站i的最小费用。 

用显然j单调递增,可用指针向后推(O(n))

注意判断INF为无解情况,可能超过变成负数,线段树记得开大


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<cctype>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (20000+10)
#define INF (2139062143)
int l[4],c[4],n,a[MAXN],st,en;
struct SegMentTree
{
	int t[MAXN*10],n,M;
	SegMentTree(){}
	SegMentTree(int _n):n(_n)
	{
		M=1;while (M-2<n) M<<=1;
		memset(t,127,sizeof(t));
	}
	void update(int x)
	{
		for (x>>=1;x;x>>=1) t[x]=min(t[x<<1],t[(x<<1)^1]);
	}
	void insert(int x,int c)
	{
		x+=M;
		if (t[x]>c)
		{
			t[x]=c;//cout<<endl<<'I'<<x<<' '<<c<<endl;
			update(x);
		}
	}
	int find(int l,int r)
	{
		if (l>r) return INF;
		l=l-1+M;r=r+1+M;
		int ans=INF;
		while (l^r^1)
		{
			if (~l&1) ans=min(ans,t[l+1]);
			if (r&1) ans=min(ans,t[r-1]);
			l>>=1;r>>=1;
		}
		return ans;
	}
}t;
void push(int &j,int L,int i)
{
	while (a[i]-a[j]>L) j++;
}
int main()
{
	scanf("%d%d%d%d%d%d%d",&l[1],&l[2],&l[3],&c[1],&c[2],&c[3],&n);
	t=SegMentTree(n);
	scanf("%d%d",&st,&en);if (st>en) swap(st,en);
	if (st==en) {cout<<"0"<<endl;return 0;	}
	a[1]=0;
	for (int i=2;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	int j[4]={st,st,st,st};
	t.insert(st,0);
	for (int i=st+1;i<=en;i++)
	{
		int value=INF;
		for (int k=1;k<=3;k++)
		{
			push(j[k],l[k],i);
//			cout<<j[k]<<' ';
			int p=t.find(j[k],i-1);
			if (p<INF) p+=c[k];
			value=min(value,p);
		}
//		cout<<value<<' '<<endl;
		t.insert(i,value);
//		for (int i=1;i<=t.M*2;i++) if (t.t[i]-INF) cout<<i<<' '<<t.t[i]<<' ';
//		cout<<endl;
	}
	cout<<t.find(en,en)<<endl;
	return 0;
}

Tyvj P2059(传递闭包)

朴素的传递闭包

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<functional>
#include<algorithm>
#include<cctype>
using namespace std;
#define MAXN (100+10)
#define MAXM (4500+10)
bool f[MAXN][MAXN]={0};
int n,m;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		f[x][y]=1;
	}
	for (int k=1;k<=n;k++)
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				f[i][j]=f[i][j]||f[i][k]&&f[k][j];
	int tot=0;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=n;j++)
			if (i!=j&&!(f[i][j]||f[j][i])) {tot--;break;}

		tot++;
	}
//	for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) cout<<f[i][j]<<' ';

	cout<<tot;
	return 0;
} 

ZOJ 1942(以路中最大边为价值的最短路)

Floyd 遍历

注意由于可能在第n步后,所以必须枚3方的

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (2000+10)
#define MAXX (1000+10)
int n,x[MAXN],y[MAXN];
double dis(int i,int j)
{
	return sqrt(pow(abs(double(x[i]-x[j])),2)+pow(abs(double(y[i]-y[j])),2));
}
double d[MAXN][MAXN];
int main()
{
	int ii=1;
	while (1)
	{
		scanf("%d",&n);
		if (n==0) break;
		for (int i=1;i<=n;i++)
		{
			scanf("%d%d",&x[i],&y[i]);
		}



	//	for (int i=1;i<=n;i++) cout<<d[i]<<' ';
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<i;j++)
				d[i][j]=d[j][i]=dis(i,j);
		}
		for (int k=1;k<=n;k++)
			for (int i=1;i<=n;i++)
				for (int j=1;j<=n;j++)
					d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));





		printf("Scenario #%dn",ii);
		printf("Frog Distance = %.3lfnn",d[1][2]);
//		cout<<d[1];



		ii++;
	}
	return 0;
}

POJ 1125(Floyd)

裸Floyd

Program P1125;
const
   maxn=100;
   maxedge=10;
   NULL=-2139062144;
var
   n,i,j,k,m,v,t,ans:longint;
   f:array[1..maxn,1..maxn] of longint;
function max(a,b:longint):longint;
begin
   if a<b then exit(b) else exit(a);
end;
begin
   read(n);
   while (n<>0) do
   begin
      fillchar(f,sizeof(f),128);
      for i:=1 to n do
      begin
         f[i,i]:=0;
         read(m);
         for j:=1 to m do
         begin
            read(v,t);
            f[i,v]:=t;
         end;
      end;

      for k:=1 to n do
         for i:=1 to n do
            for j:=1 to n do
               if (f[i,k]<>NULL) and (f[k,j]<>NULL) then
                  if (f[i,k]+f[k,j]<f[i,j]) or (f[i,j]=NULL) then f[i,j]:=f[i,k]+f[k,j];
      ans:=maxlongint;

      v:=0;
      for i:=1 to n do
      begin
         t:=f[i,1];
         for j:=1 to n do
         begin
            if f[i,j]=NULL then break else t:=max(f[i,j],t);
         end;
         if f[i,j]=NULL then continue;
         if t<ans then begin v:=i; ans:=t; end;

      end;
      if (ans=maxlongint) then writeln('disjoint') else writeln(v,' ',ans);



      read(n);
   end;
end.

POJ 3256(SPFA)

这题只能对每一个点查一遍……

有向图的话能用floyd,可是迫于时限用了SPFA。

Program aa;
const
   maxk=10000;
   maxn=10000;
   maxm=10000;
var
   k,n,m,i,j,l:longint;
   a:array[1..maxk] of longint;
   q:array[1..maxn] of longint;
   edge,next,head:array[1..maxm] of longint;
   size:longint;
   res,num,b:array[1..maxn] of boolean;

procedure add(u,v:longint);
begin
   inc(size);
   edge[size]:=v;
   next[size]:=head[u];
   head[u]:=size;
end;


procedure spfa;
var
   i,j,p,now,v:longint;
begin
   i:=1;j:=1;
   while (i<=j) do
   begin
      now:=q[i];
      p:=head[now];
      while p<>0 do
      begin
         v:=edge[p];
         if not(b[v]) then
         begin
            b[v]:=true;
            inc(j);
            q[j]:=v;
         end;



         p:=next[p];
      end;
      inc(i);
   end;
   for i:=1 to n do
      res[i]:=res[i] and b[i];

end;

begin
   size:=0;
   fillchar(head,sizeof(head),0);
   fillchar(edge,sizeof(edge),0);
   fillchar(next,sizeof(next),0);
   fillchar(b,sizeof(b),false);
   fillchar(res,sizeof(res),true);
   fillchar(num,sizeof(num),false);
   read(k,n,m);
   for i:=1 to k do read(a[i]);
   for i:=1 to m do
   begin
      read(j,l);
      add(j,l);
   end;

   for i:=1 to k do
      if not(num[a[i]]) then
      begin
         num[a[i]]:=true;
         q[1]:=a[i];
         fillchar(b,sizeof(b),false);
         b[q[1]]:=true;
         spfa;
      end;
   l:=0;
   for i:=1 to n do if res[i] then inc(l);
   writeln(l);



end.

POJ 3259(负权回路)

注意普通路径是双向的

program P3259;
var
   f,n,m,w,i,j:longint;
   s,e,t:longint;
   map:array[1..2500,1..3] of longint;
   wmap:array[1..300,1..3] of longint;
   d:array[1..2500] of longint;
   flag:boolean;
procedure relax(u,v,w:longint);
begin
   if (d[v]>d[u]+w) then
   begin
      d[v]:=d[u]+w;
      flag:=false;
   end;
end;
procedure bellman_ford;
var
   i,j:longint;
begin
   for i:=1 to n do
   begin
      flag:=true;
      for j:=1 to m do
      begin
         relax(map[j,1],map[j,2],map[j,3]);
         relax(map[j,2],map[j,1],map[j,3]);

      end;
      for j:=1 to w do relax(wmap[j,1],wmap[j,2],-wmap[j,3]);
      if flag then break;
   end;

   if flag then writeln('NO') else writeln('YES');
end;
begin
   read(f);
   while f>0 do
   begin
      fillchar(map,sizeof(map),0);
      fillchar(wmap,sizeof(wmap),0);
      fillchar(d,sizeof(d),0);

      read(n,m,w);
      for i:=1 to m do
      begin
         read(map[i,1],map[i,2],map[i,3]);
      end;
      for i:=1 to w do read(wmap[i,1],wmap[i,2],wmap[i,3]);
      bellman_ford;
      dec(f);
   end;
end.