在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
【题目链接】http://acm.hdu.edu.cn/showproblem.php?pid=6808 【题目大意】 坐标轴上,人可以选择自己开始跑步的时间、位置、方向(正方向/负方向) 有n个观测点给出观测时间和坐标,此处此时至少有一个人跑步,问最少有几个人跑步
ps:数据量太大,需要用dinic跑最大流 1 #include<bits/stdc++.h> 2 using namespace std; 3 int const maxn=2e5+7,maxn2=1e5+7;; 4 typedef long long ll; 5 const ll inf=1e18; 6 int s,t,n,id1[maxn],id2[maxn],fr[maxn2],to[maxn2],numid1,numid2,tot; 7 int cur[maxn],head[maxn],deep[maxn]; 8 void init(){ 9 memset(id1,0,sizeof(id1)); 10 memset(id2,0,sizeof(id2)); 11 memset(head,-1,sizeof(head)); 12 numid1=0; 13 numid2=0; 14 tot=-1; 15 } 16 struct edge{ 17 int to,nxt; 18 ll flow; 19 }e[maxn*6]; 20 void build(int x,int y,int z){ 21 e[++tot].to=y; 22 e[tot].flow=z; 23 e[tot].nxt=head[x]; 24 head[x]=tot; 25 // printf("%d : %d %d \n",tot,x,y,z); 26 } 27 //二分图反相边 28 void build_dinci(int x,int y,int z){ 29 e[++tot].to=y;e[tot].flow=z;e[tot].nxt=head[x];head[x]=tot; 30 e[++tot].to=x;e[tot].flow=0;e[tot].nxt=head[y];head[y]=tot; 31 } 32 queue<int>q; 33 int bfs(){ 34 while(!q.empty())q.pop(); 35 memset(deep,0,sizeof(deep)); 36 deep[s]=1; 37 q.push(s); 38 while(!q.empty()){ 39 int u=q.front();q.pop(); 40 for(int i=head[u];i!=-1;i=e[i].nxt){ 41 if(e[i].flow&&!deep[e[i].to]){//要还有流量 42 deep[e[i].to]=deep[u]+1; 43 q.push(e[i].to); 44 } 45 } 46 } 47 return deep[t]; 48 } 49 ll dfs(int u,ll limit){ 50 if(u==t)return limit; 51 for(int &i=cur[u];i!=-1;i=e[i].nxt){//当前弧优化 i是cur[i],下一个还没被访问过的边 52 //int& 是引用,变量别名,修改i就修改了cur[u] 53 int v=e[i].to; 54 if(deep[v]==deep[u]+1&&e[i].flow){//u只能由deep[u]-1到达 55 ll nowdi=dfs(v,min(limit,e[i].flow)); 56 if(nowdi){ 57 e[i].flow-=nowdi; 58 e[i^1].flow+=nowdi; 59 return nowdi; 60 } 61 } 62 } 63 return 0; 64 } 65 ll dinic(){ 66 ll ans=0; 67 while(bfs()){ 68 for(int i=1;i<=n;i++)//bfs分层 69 cur[i]=head[i]; 70 ll d=dfs(s,inf); 71 while(d){ 72 ans+=d;//寻找增广路 73 d=dfs(s,inf); 74 } 75 } 76 return ans; 77 } 78 int main(){ 79 int T,a,b; 80 scanf("%d",&T); 81 while(T--){ 82 scanf("%d",&n); 83 init(); 84 for(int i=1;i<=n;i++){ 85 scanf("%d%d",&a,&b); 86 fr[i]=b-a+1e5,to[i]=b+a; 87 //把图旋转45°,转化成画平行于x或者y轴的线,y-x y+x 88 if(!id1[fr[i]])id1[fr[i]]=++numid1; 89 if(!id2[to[i]])id2[to[i]]=++numid2; 90 } 91 /*planb 92 先存下来,然后离散化(用时间换空间) 93 (此处用空间换时间) 94 95 题意概述: 96 人可以选择自己开始跑步的位置和方向,问最少有几个人跑步 97 转变为选最少的直线(斜率为1或-1)覆盖坐标中的点 98 可以把坐标旋转45°,转变为画平行于x或y轴的直线覆盖所有点 99 100 把点的x坐标和y坐标分别作为二分图中两侧的点,连边 101 转变为二分图最小点覆盖的问题 。最小点覆盖=二分图最大匹配 ,数据量太大,需要用dinic跑最大流 102 */ 103 s=numid1+numid2+1,t=s+1; 104 for(int i=1;i<=n;i++){ 105 build_dinci(id1[fr[i]],id2[to[i]]+numid1,1); 106 } 107 //注意二分图两边的点, 只和源点/汇点 加一次!! 108 for(int i=1;i<=numid1;i++){ 109 build_dinci(s,i,1); 110 } 111 for(int i=1;i<=numid2;i++){ 112 build_dinci(i+numid1,t,1); 113 } 114 n=numid1+numid2+2; 115 ll ans=dinic(); 116 printf("%lld\n",ans); 117 118 } 119 return 0; 120 }
|
请发表评论