2021-03-29

TOC【吴永辉】程序设计基础实践7-9I-L

I. The Balance
题意:求ax+by=c中|x|+|y|的最小值。

先解决ax+by=c对于x的最小正整数解,再解决对于y的最小正整数解,按照他的排序要求,找到最小的那个即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll exgcd(ll a,ll b,ll &x,ll &y){
	ll d;
	if(b){
	    d=exgcd(b,a%b,y,x);
		y-=a/b*x;
		return d;
	}
	x=1;
	y=0;
	return a;
}
ll ab(ll x){
	return x>0?x:-x;
}
ll w1,w2,c;
void work(){
	ll d,anx,any,min1=2147483647,min2=2147483647,x,y;
	d=exgcd(w1,w2,anx,any);
	anx=anx*c/d;any=any*c/d;
	x=anx;
	y=any;
	anx=(anx%(w2/d)+w2/d)%(w2/d);
	any=any-(anx-x)/(w2/d)*(w1/d);
	min1=ab(anx)+ab(any);
	min2=anx*w1+any*w2;
	x=anx;
	y=any;
	any=(any%(w1/d)+w1/d)%(w1/d);
	anx=anx-(any-y)/(w1/d)*(w2/d);
	if(min1>ab(anx)+ab(any)){
		x=anx;y=any;
	}
	if(min1==ab(anx)+ab(any)){
		if(min2>anx*w1+any*w2){
			x=anx;
			y=any;
		}
	}
	cout<<ab(x)<<" "<<ab(y)<<endl;
}
int main()
{
    while(scanf("%lld%lld%lld",&w1,&w2,&c)!=EOF){
		if(w1==0&&w2==0&&c==0)break;
		work();
    }
    return 0;
}

J. ID Codes
题意:找出字典序的下一个排列,如果一直是递减的,就输出“No Successor”。

1.用的是STL的模板
头文件:
函数名 next_permutation(参数)
作用:寻找当前序列的下一个排序(按字典序的顺序)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    while(cin>>s&&s!="#"){
    	if(next_permutation(s.begin(),s.end()))
			cout<<s<<endl; 
		else
			cout<<"No Successor"<<endl;
	}
	return 0;
}

2.找下一个比他大的串,从后往前遍历,对当前i考虑i后的j,若a[i]<a[j],进行交换(a[j]取成立中最小的),并对i后的字符排序即可输出并退出循环。

#include<bits/stdc++.h>
using namespace std;
int cmp(const void*a,const void *b)
{
    return  *(int *)a-*(int *)b;
}
int main()
{
    int i,j,m,n;
    char a[110];
    while(cin>>a&&a[0]!='#'){
       int k=strlen(a);
	   char t;
       for(i=k-2;i>=0;i--){
	        char min=a[i];
	        int flag=0;
            for(j=i+1;j<k;j++){
                if(a[j]>a[i]&&!flag){
                    min=a[j];flag=1;
                }
                else if(a[j]<min&&a[j]>a[i]&&flag) min=a[j];
            }
            if(min!=a[i]){
                for(j=i+1;j<k;j++){
                    if(min==a[j]){
                        t=a[i];a[i]=a[j];a[j]=t;
                        for(m=i+1;m<k;m++){
                        for(n=m+1;n<k;n++){
                        if(a[m]>a[n]){
                            t=a[m];a[m]=a[n];a[n]=t;
                        }}}
                        puts(a);
	        break;
                    }
                }
            }
            if(j<k) break;
        }
       if(i<0) cout<<"No Successor"<<endl;
    }
    return 0;
}

K. Schedule
题意:给n个任务的开始和结束时间,求最少用机器,和在这些机器上用的最少时间

#include<bits/stdc++.h>
using namespace std;
struct node{
    int l,r;
    bool operator <(const node a)const{
        return l<a.l;
    }
}seg[];
multiset<int>s;
multiset<int>::iterator it;
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        s.clear();
        int n;
        scanf("%d",&n);
        for(int i=;i<n;i++)
        {
            scanf("%d %d",&seg[i].l,&seg[i].r);
        }
        int ans = ;//记录所用机器数量
        long long res = ;//记录时间
        sort(seg,seg+n);
        for(int i=;i<n;i++)
        {
            it = s.upper_bound(seg[i].l);//寻找 >= seg[i].l 的r
            if(it == s.begin())
            {
                ans++;   //找不到 就重新开一个机器
                res += seg[i].r - seg[i].l;
                s.insert(seg[i].r);
                continue;
            }
            it--;//这里就是离该i区间的起始点最近的 结束点
            res += seg[i].r - *it;//把该i区间的结束点 接上上个结束点 这样就不用管 起始点在哪里了
            s.erase(it);//把当前区间结束点删除
            s.insert(seg[i].r);//重新更新
        }
        cout<<ans<<" "<<res<<endl;
    }
}

L. Brackets Sequence

定义合法的括号序列如下:

1 空序列是一个合法的序列

2 如果S是合法的序列,则(S)和[S]也是合法的序列

3 如果A和B是合法的序列,则AB也是合法的序列

#include<bits/stdc++.h>
using namespace std;
 
const int N = 105;
const int SUP = 2e9;
int d[N][N], pos[N][N];
char s[N];
 
void match(int len)
{
	for(int i = 0; i < len; i++)
		d[i][i] = 1;//d值的含义:i和i+k之间应该添加的括号。起始条件:d[i][i] = 1;
	for(int k = 1; k < len; k++)//枚举间隔
		for(int i = 0; i + k < len; i++) {//枚举起点
			d[i][i+k] = SUP;
			if((s[i] == '(' && s[i+k] == ')') || (s[i] == '[' && s[i+k] == ']')) {//匹配
				d[i][i+k] = d[i+1][i+k-1];
				//情况一:左右交换:1。情况二:左右相等:1。情况三:内部需要几个它就需要几个
				pos[i][i+k] = -1;
			}
			for(int tmp = i; tmp < i + k; tmp++)//枚举分界点
			if(d[i][i+k] > d[i][tmp] + d[tmp+1][i+k]) {//DP
				pos[i][i+k] = tmp;//该点处分开,解更优
				d[i][i+k] = d[i][tmp] + d[tmp+1][i+k];//状态转移
			}
		}
}
 
void PR(int l, int r)
{
	if(l > r)	return;//递归边界
	if(l == r) {
		if(s[l] == '(' || s[l] == ')')
			printf("()");
		else
			printf("[]");
	}
	else {
		if(pos[l][r] == -1) {//匹配,则递归输出内部
			putchar(s[l]);
			PR(l+1, r-1);
			putchar(s[r]);
		}
		else {//不匹配,则递归至最优分界点
			PR(l, pos[l][r]);
			PR(pos[l][r]+1, r);
		}
	}
}
 
int main()
{
	scanf("%s", s);
	int len = strlen(s);
	match(len);
	PR(0, len-1);//递归输出解
	putchar('\n');
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值