upc 6445: 棋盤V (網路流費用流解決匹配問題)
6445: 棋盤V
時間限制: 1 Sec 記憶體限制: 128 MB
提交: 325 解決: 31
[提交] [狀態] [討論版] [命題人:admin]
題目描述
有一塊棋盤,棋盤的邊長為100000,行和列的編號為1到100000。棋盤上有n個特殊格子,任意兩個格子的位置都不相同。
現在小K要猜哪些格子是特殊格子。她知道所有格子的橫座標和縱座標,但並不知道對應關係。換言之,她只有兩個陣列,一個存下了所有格子的橫座標,另一個存下了所有格子的縱座標,而且兩個陣列都打亂了順序。當然,小K猜的n個格子的位置也必須都不相同。
請求出一個最大的k,使得無論小K怎麼猜,都能猜對至少k個格子的位置。
輸入
輸入資料第一行包含一個整數n。
接下來n行,每行描述一個特殊格子的位置。第i行含有兩個整數xi和yi ,代表第i個格子的座標。保證任意兩個格子的座標都不相同。
輸出
輸出一行,包含一個整數,代表最大的k。
樣例輸入
2 1 1 2 2
樣例輸出
0
提示
小K有可能會猜(1,2),(2,1),此時一個都沒對
對於30%的資料,n≤8。
另外有5%的資料,所有橫座標和縱座標均不相同。
另外有15%的資料,所有橫座標或者縱座標均不相同。
對於100%的資料,n≤50,1≤xi,yi≤100000。
來源/分類
【題意】
對於題意,應該理解為,小K儘量猜錯。
對於給出的座標x和y,完成一個一一匹配,使得匹配完成後,與原座標重複的最少。
【分析】
貌似是一個帶權二分圖匹配問題,沒試過KM演算法是否可行。我用的費用流。
對輸入的座標離散化一下,方便建圖。
列舉x座標和y座標,若(x,y)之間是正確邊,則建邊容量=1,費用=1;否則,建邊容量=1,費用=0;
虛擬源點0,匯點maxver(一個很大的不存在的編號即可)
對0到所有的x座標建邊,容量為x行所含做標數,費用=0
對所有y到maxver建邊,容量為y列所含做標數,費用=0;
對此圖跑一遍費用流,按照費用流策略,優先走費用為0的邊,即錯誤邊,錯誤邊滿流時,不得不走正確邊,花費1.
故最後的費用流即為不得不猜對的座標。
【程式碼】
/**** ***author: winter2121 ****/ #include<bits/stdc++.h> #define rep(i,s,t) for(int i=s;i<=t;i++) #define SI(i) scanf("%d",&i) #define PI(i) printf("%d\n",i) using namespace std; typedef long long ll; const int mod=1e9+7; const int MAX=4e2+5; const int INF=0x3f3f3f3f; const double eps=1e-8; int dir[9][2]={0,1,0,-1,1,0,-1,0, -1,-1,-1,1,1,-1,1,1}; template<class T>bool gmax(T &a,T b){return a<b?a=b,1:0;} template<class T>bool gmin(T &a,T b){return a>b?a=b,1:0;} template<class T>void gmod(T &a,T b){a=(a%mod+b)%mod;} struct node{ int s,t,len,cap,flow,next; }e[MAX*MAX];//len路長,cap最大流量,flow已流的量 int head[MAX],cnt; void add(int u,int v,int len,int cap,int flow=0) { e[cnt]=node{u,v,len,cap,flow,head[u]}; head[u]=cnt++; } int dis[MAX];//最短路 bool inq[MAX]; int f[MAX];//流量 int pre[MAX];//前驅邊 bool spfa(int s,int t,int &flow,int &cost,int ver) //ver是最大點編號 { for(int i=0;i<=ver;i++)dis[i]=INF; memset(inq,0,sizeof(inq)); dis[s]=0;f[s]=INF; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front();q.pop(); inq[u]=0; for(int i=head[u];~i;i=e[i].next) { if(e[i].cap-e[i].flow>0&&dis[e[i].t]>dis[u]+e[i].len) //只要有流量,並且路徑變短 { f[e[i].t]=min(f[u],e[i].cap-e[i].flow); dis[e[i].t]=dis[u]+e[i].len; pre[e[i].t]=i; if(!inq[e[i].t]) q.push(e[i].t),inq[e[i].t]=1; } } } if(dis[t]==INF) return 0; //沒走到終點 flow+=f[t]; //本條增廣路的流量 cost+=dis[t]*f[t]; //花費 for(int u=t;u!=s;u=e[pre[u]].s) { e[pre[u]].flow+=f[t]; e[pre[u]^1].flow-=f[t]; } return 1; } int mincost(int s,int t,int ver) { int flow=0,cost=0; while(spfa(s,t,flow,cost,ver)); return cost; } int n; int cx[MAX],cy[MAX]; int x[MAX],y[MAX]; int hax[MAX],hay[MAX]; int mmp[100][100]; int main() { memset(head,-1,sizeof(head)); cnt=0; SI(n); for(int i=1;i<=n;i++) { SI(x[i]);SI(y[i]); hax[i]=x[i],hay[i]=y[i]; } sort(hax+1,hax+n+1); sort(hay+1,hay+n+1); int topx=unique(hax+1,hax+n+1)-hax-1; int topy=unique(hay+1,hay+n+1)-hay-1; rep(i,1,n) { int xx=lower_bound(hax+1,hax+1+topx,x[i])-hax; int yy=lower_bound(hay+1,hay+1+topy,y[i])-hay; cx[xx]++; cy[yy]++; mmp[xx][yy]=1; } rep(i,1,topx) { rep(j,1,topy) { add(i,j+topx,mmp[i][j],1); add(j+topx,i,-mmp[i][j],0); //cout<<xx<<' '<<yy<<' '<<(i==j)<<endl; } } rep(i,1,topx) { add(0,i,0,cx[i]); add(i,0,0,0); } rep(i,1,topy) { add(i+topx,topx+topy+1,0,cy[i]); add(topx+topy+1,i+topx,0,0); } ll ans=mincost(0,topx+topy+1,topx+topy+1); printf("%lld\n",ans); } /* 4 1 1 2 2 3 3 1 3 ans=1 5 1 1 2 2 3 3 4 4 1 4 ans=0 */