spfa+差分约束系统(D - POJ - 1201 && E - POJ - 1364&&G - POJ - 1)+建边的注意事项+超级源点的建立

题目链接:https://cn.vjudge.net/contest/276233#problem/D

给出n个闭合的整数区间[ai,bi]和n个整数c1,…,cn。

编写一个程序:
从标准输入中读取间隔数,它们的端点和整数c1,…,cn,
计算具有间隔[ai,bi]的至少ci共同元素的整数集合Z的最小尺寸,对于每个i = 1,2,…,n,

 具体思路:首先,我们假设存在一个数组s,s[i]记录的是第i个点到第0个点的需要取出的点的个数,对于题目中的从(A,B)至少有d个,我们就可以将这个条件变成posB-(posA-1)>=d,也就是(posA-1)-posB<=-d,这一段的边就建立好了,但是对于这个区间内的每一个数,我们的范围是没有限制的,但是如果没有限制会出现下列情况,s[i]>=i,也就是说会出现矛盾,所以对于这个区间内的没一个数都需要限制,也就是对于区间(i,i+1),我们可以引申出如下条件。0=<pos(i+1)-pos(i)<=1,

也就是 pos[i+1]-pos[i]>=0(pos[i]-pos[i+1]<=0),和 pos[i+1]-pos[i]<=1,也就是把这段区间的每一个小的区间的条件设立好了就可以了。(注意建边的时候注意方向)

AC代码:

 1 #include<bits/stdc++.h>
 9 using namespace std;
10 # define ll long long
11 # define inf 0x3f3f3f3f
12 const int maxn = 50000+100;
13 const int maxedge= 1000000+10;
14 int num,head[maxn];
15 int dis[maxn],vis[maxn];
16 int minx=inf;
17 int maxy=0;
18 struct node
19 {
20     int fr;
21     int to;
22     int cost;
23     int nex;
24 } edge[maxedge];
25 struct point
26 {
27     int st;
28     int ed;
29 } po[maxn];
30 void init()
31 {
32     for(int i=0; i<=50000; i++)
33     {
34         head[i]=-1;
35         vis[i]=0;
36         dis[i]=inf;
37     }
38     num=0;
39 }
40 void addedge(int fr,int to,int cost)
41 {
42     edge[num].to=to;
43     edge[num].cost=cost;
44     edge[num].nex=head[fr];
45     head[fr]=num++;
46 }
47 ll spfa(int st,int ed)
48 {
49     dis[st]=0;
50     vis[st]=1;
51     queue<int>q;
52     q.push(st);
53     while(!q.empty())
54     {
55         int tmp=q.front();
56         q.pop();
57         vis[tmp]=0;
58         for(int i=head[tmp]; i!=-1; i=edge[i].nex)
59         {
60             int u=edge[i].to;
61             if(dis[u]>dis[tmp]+edge[i].cost)
62             {
63                 dis[u]=dis[tmp]+edge[i].cost;
64                 if(vis[u])
65                     continue;
66                 vis[u]=1;
67                 q.push(u);
68             }
69         }
70     }
71     return dis[ed];
72 }
73 int main()
74 {
75     int n,d;
76     scanf("%d",&n);
77     init();
78     for(int i=1; i<=n; i++)
79     {
80         scanf("%d %d %d",&po[i].st,&po[i].ed,&d);
81         addedge(po[i].st-1+1,po[i].ed+1,-d);//两个左边都+1,是为了防止出现变成-1的情况。
82         minx=min(minx,po[i].st);
83         maxy=max(maxy,po[i].ed+1);
84     }
85     for(int i=minx; i<=maxy-1; i++)
86     {
87         addedge(i,i+1,0);
88         addedge(i+1,i,1);
89     }
90     int ans=spfa(minx,maxy);
91     printf("%d\n",-ans);
92     return 0;
93 }
94 

E:

n个数的一个序列,m个约数,si, ni, oi, ki, 代表了序列中第si个数到第si+ni个数的和大于或小于ki,gt = 大于,lt = 小于

问是否存在相悖的约束

一个由memset引发的惨案,,,本来是用for循环初始化来着,结果这个题用for一直wa(后来发现是越界了--),然后改成memset的化就给过了。但是顺便加深了对建图的理解(理解写在上面了)。

AC代码:

   #include<bits/stdc++.h>
  9 using namespace std;
 10 # define ll long long
 11 # define inf 0x3f3f3f3f
 12 const int maxn = 50000+100;
 13 const int maxedge= 1000000+10;
 14 int num,head[maxn],out[maxn];
 15 int dis[maxn],vis[maxn];
 16 int n,m;
 17 struct node
 18 {
 19     int fr;
 20     int to;
 21     int cost;
 22     int nex;
 23 } edge[maxedge];
 24 struct point
 25 {
 26     int st;
 27     int ed;
 28 } po[maxn];
 29 void init()
 30 {
 31     for(int i=0; i<maxn; i++)
 32     {
 33         vis[i]=0;
 34         dis[i]=inf;
 35         head[i]=-1;
 36         out[i]=0;
 37     }
 38     num=0;
 39     num=0;
 40 }
 41 void addedge(int fr,int to,int cost)
 42 {
 43     edge[num].to=to;
 44     edge[num].cost=cost;
 45     edge[num].nex=head[fr];
 46     head[fr]=num++;
 47 }
 48 ll spfa(int st)
 49 {
 50     dis[st]=0;
 51     vis[st]=1;
 52     queue<int>q;
 53     q.push(st);
 54     while(!q.empty())
 55     {
 56         int tmp=q.front();
 57         q.pop();
 58         if(++out[tmp]>n+3)
 59             return -1;
 60         vis[tmp]=0;
 61         for(int i=head[tmp]; i!=-1; i=edge[i].nex)
 62         {
 63             int u=edge[i].to;
 64             if(dis[u]>dis[tmp]+edge[i].cost)
 65             {
 66                 dis[u]=dis[tmp]+edge[i].cost;
 67                 if(vis[u])
 68                     continue;
 69                 vis[u]=1;
 70                 q.push(u);
 71             }
 72         }
 73     }
 74     return 1;
 75 }
 76 int main()
 77 {
 78     while(cin>>n)
 79     {
 80         init();
 81         if(n==0)
 82             break;
 83         cin>>m;
 84         int u,v,d;
 85         string str;
 86         for(int i=1; i<=m; i++)
 87         {
 88             cin>>u>>v>>str>>d;
 89             if(str=="gt")
 90             {
 91                 addedge(u,u+v+1,-(d+1));
 92             }
 93             else
 94             {
 95                 addedge(v+u+1,u,d-1);
 96             }
 97         }
 98         for(int i=1; i<=n+1; i++)
 99         {
100             addedge(102,i,0);//超级源点的建立过程
101         }
102         int ans=spfa(102);
103         if(ans==-1)
104             cout<<"successful conspiracy"<<endl;
105         else
106             cout<<"lamentable kingdom"<<endl;
107     }
108     return 0;
109 }
110  

 

G题:

给出数轴上的n个闭合int型区间。现在要在数轴上任意取一堆元素,构成一个元素集合V,要求给出的每个区间和元素集合V的交集至少有两个不同的元素,求集合V最小的元素个数。

超级源点的建立,为了保证整个区间的连通的,我们就需要建立一个超级源点来使得整个图是连通的,但是注意一点,在正常建边的时候,如果是大的指向小的,这个时候我们建立超级源点的时候就也应该遵循这个原则,如果是是小的指向大的,我们建立超级源点的时候反过来就可以了。

AC代码:

   #include<bits/stdc++.h>
 9 using namespace std;
10 # define ll long long
11 # define inf 0x3f3f3f3f
12 const int maxn = 10000+100;
13 const int maxnedge=1000000+100;
14 struct node
15 {
16     int nex;
17     int to;
18     int cost;
19 } edge[maxnedge];
20 int head[maxn],vis[maxn],dis[maxn],num;
21 void init()
22 {
23     memset(head,-1,sizeof(head));
24     memset(vis,0,sizeof(vis));
25     memset(dis,inf,sizeof(dis));
26     num=0;
27 }
28 void addedge(int fr,int to,int cost)
29 {
30     edge[num].to=to;
31     edge[num].nex=head[fr];
32     edge[num].cost=cost;
33     head[fr]=num++;
34 }
35 int spfa(int st,int ed)
36 {
37     queue<int>q;
38     dis[st]=0;
39     vis[st]=1;
40     q.push(st);
41     while(!q.empty())
42     {
43         int tmp=q.front();
44         q.pop();
45         vis[tmp]=0;
46         for(int i=head[tmp]; i!=-1; i=edge[i].nex)
47         {
48             int u=edge[i].to;
49             if(dis[u]>dis[tmp]+edge[i].cost)
50             {
51                 dis[u]=dis[tmp]+edge[i].cost;
52                 if(vis[u])
53                     continue;
54                 vis[u]=1;
55                 q.push(u);
56             }
57         }
58     }
59     return dis[ed];
60 }
61 int main()
62 {
63     init();
64     int n;
65     scanf("%d",&n);
66     int u,v;
67     int minx=inf,maxy=0;
68     for(int i=1; i<=n; i++)
69     {
70         scanf("%d %d",&u,&v);
71         u+=10;
72         v+=10;
73         addedge(u-1,v,-2);
74         addedge(v,u-1,v-u+1);
75         minx=min(minx,u-1);
76         maxy=max(maxy,v);
77     }
78     int st=maxy+1;
80     for(int i=minx; i<maxy; i++){
82         addedge(st,i,0);
83         addedge(i,i+1,0);
84         addedge(i+1,i,1);
85     }
86     addedge(st,maxy,0);
88     int ans=spfa(st,maxy);
89     printf("%d\n",-ans);
90     return 0;
91 }
92  

 

posted @ 2018-12-19 15:43  Let_Life_Stop  阅读(208)  评论(0编辑  收藏  举报