题目链接: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 ",-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 ",-ans); 90 return 0; 91 } 92