AtCoder Beginner Contest 320 G - Slot Strategy 2

考虑机器对于每个数字 i i i所能达到的最短时间,对于一个数字 i i i,若其能够在时间 t t t内统一,那么其也一定能在时间 2 t 2t 2t内统一,所以对于每个数字的最小花费具有单调性,因此考虑二分。
考虑二分的check函数,因为同一个时间点我们只能操作一台机器,所以对于n台机器,我们考虑其是否能够在 m i d mid mid时间内呈现出数字 i i i:由此可以联想到二分图的最大匹配,即我们将n台机器看作左部,将时间看作右部,那么此刻就转换为了该二分图是否匹配。

#include 

using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 1e9+7;
const int maxv = 4e6 + 5;
// #define endl "\n"

int n,m;
string s[105];
vector<int> e[15][105];//e[i][j]表示第i个数字所在的j机器出现数字i的时间
map<int,int> st,f;//因为值域为1e9,所以使用map,数组没试过memset会不会超时
bool find(int x,int mid,int dig)//匈牙利算法,x为点的下标,mid为时间上限,dig表示第几台机器
{
	for(auto u: e[dig][x]){
		for(int i=u;i<=mid;i+=m){
			if(st[i]) continue;
			st[i]=1;
			if(!f[i]||find(f[i],mid,dig)) {
				f[i]=x;
				return true;
			}
		}
	}
	return false;
}

bool check(int mid,int dig)//check函数,
{
	f.clear();
	for(int i=1;i<=n;i++){
		st.clear();
		if(!find(i,mid,dig)) return false;
	}
	return true;
}


void solve()
{	
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>s[i];
		int cnt=0;
		for(auto x: s[i]){
			e[x-'0'][i].push_back(cnt);
			cnt++;
		}
	}
	ll ans=2e9;
	for(int i=0;i<=9;i++){//对于每个数字去二分然后取最小值
		ll res=2e9;
		int l=0,r=n*m;
		while(l<=r){
			int mid=(l+r)/2;
			if(check(mid,i)){
				res=mid;
				r=mid-1;
			}
			else{
				l=mid+1;
			}
		}
		ans=min(ans,res);
	}
	if(ans==2e9) cout<<-1<<endl;
	else cout<<ans<<endl;
}

int main()
{
    ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	//cin>>t;
	while(t--){
		solve();
	}
    system("pause");
    return 0;
}

你可能感兴趣的:(补题记录,算法)