组队赛3解题报告:精度与二进制枚举

E题:ACM-ICPC Live Archive 6448 - Credit Card Payment

Using credit cards for your purchases is convenient, but they have high
interest rates if you do not pay your balance in full each month.
The interest rate is commonly quoted in terms of \annual percentage
rate" (APR) which is then applied to the outstanding balance each
month. The APR can be converted to a monthly interest rate R. At
the end of each month, the monthly interest rate is applied to the
outstanding balance and the interest is added to the total balance. Any
payment made will be applied to the balance in the following month.
The monthly interest is rounded to the nearest cent (rounding up 0.5 cent and above) in the calculations.
You have unfortunately accumulated an outstanding balance B at the end of the month and you
can only a ord to pay up to some amount M every month. If you do not make any more purchases
with the credit card, what is the minimum number of payments needed to completely eliminate the
outstanding balance? It is possible that you cannot pay o the balance in 100 years (1200 payments).
Input
The input consists of multiple test cases. The rst line of input is a single integer, not more than 1000,
indicating the number of test cases to follow. Each of the following lines specify the input for one case.
Each line contains three positive real numbers separated by single spaces: R, B, and M. The real
numbers have two digits after the decimal point, satisfying R  50:00 and B; M  50000:00. R is the
monthly interest rate and is speci ed as a percentage.
Output
For each case, display on a line the minimum number of payments needed to eliminate the outstanding
balance. If this cannot be done in at most 1200 payments, print instead `impossible'.
Sample Input
11
2.00 100.00 105.00
2.00 100.00 102.00
2.00 100.00 100.00
2.00 100.00 4.00
2.00 100.00 3.00
2.00 100.00 1.00
2.00 100.00 2.00
9.56 5462.50 522.22
12.50 29876.44 33610.99
5.50 1.00 1.05
14.78 40181.09 46119.86
Sample Output
1
1
2
36
56
impossible
impossible
impossible
2
2
1

这题与精度有关,而以前关于精度几乎没做过,所以这题……就这样完蛋了……唉……

回来研究队友的代码好久才知道是哪出问题导致当时没过了……

在解决需要还的款项中0.5这个精度的时候,唉……没有加上eps,然后因为double的精度有所损失,就一直WA。但是加上eps后,样例的倒数第二个还是没过,然后又改了好久,因为当时设置的eps是1e-10,所以还是错了,改成1e-7了才过……晕……看来得做精度方面的几道题才行。

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define eps 1e-7
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define MM 2000002
#define MN 305
#define INF 1000000007
using namespace std;
typedef long long ll;
int main()
{
    int t,j;
    scanf("%d",&t);
    while(t--)
    {
        double a,b,c,d,a1;
        ll b1,c1,e;
        int ans=0;
        scanf("%lf%lf%lf",&a,&b,&c);
        a1=a/100;
        b1=b*100+eps;
        c1=c*100+eps;
        e=a1*b1+0.5;
        //利息比每月还的还大的话就肯定不行了
        if(e>c1) {puts("impossible");continue;}
        for(j=1;j<=1200;j++)
        {
            e=a1*b1+0.5;
            //printf("%lld %lld\n",e,b1);
            b1=b1+e-c1;
            if(b1<=0) {ans=1;break;}
        }
        if(ans) pri(j);
        else puts("impossible");
    }
    return 0;
}

G题:Social Advertising

6450 Social Advertising
You have decided to start up a new social networking company. Other existing popular social networks
already have billions of users, so the only way to compete with them is to include novel features no
other networks have.
Your company has decided to market to advertisers a cheaper way to charge for advertisements (ads).
The advertiser chooses which users' \wall" the ads would appear on, and only those ads are charged.
When an ad is posted on a user's wall, all of his/her friends (and of course the user himself/herself)
will see the ad. In this way, an advertiser only has to pay for a small number of ads to reach many
more users.
You would like to post ads to a particular group of users with the minimum cost. You already have
the \friends list" of each of these users, and you want to determine the smallest number of ads you have
to post in order to reach every user in this group. In this social network, if A is a friend of B, then B
is also a friend of A for any two users A and B.
Input
The input consists of multiple test cases. The rst line of input is a single integer, not more than
10, indicating the number of test cases to follow. Each case starts with a line containing an integer n
(1  n  20) indicating the number of users in the group. For the next n lines, the ith line contains the
friend list of user i (users are labelled 1; : : : ; n). Each line starts with an integer d (0  d < n) followed
by d labels of the friends. No user is a friend of himself/herself.
Output
For each case, display on a line the minimum number of ads needed to be placed in order for them to
reach the entire group of users.
Sample Input
2
5
4 2 3 4 5
4 1 3 4 5
4 1 2 4 5
4 1 2 3 5
4 1 2 3 4
5
2 4 5
2 3 5
1 2
2 1 5
3 1 2 4
Sample Output
1
2

这题还是挺神的,经OE大帝提醒,然后就用了二进制枚举做。邻边我用了邻接表+了一个for判断就T了,唉……逗,经范神提醒,才记得用二进制也可以像邻接表那样记录点的边的……二进制中第几位为1就是结点另一个结点的关系,然后合并如果二进制中每一位都为1( 这个与下面用vis数组记录为1是一样的效果,不过用邻接表太慢了,时间与10^6*20*20),就说明选举的点其边已经可以覆盖所有的结点了,就这符合了答案所求的了……

下面第一个代码是用邻接表做的T了:

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define eps 1e-7
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define MM 2000002
#define MN 305
#define INF 1000000007
using namespace std;
typedef long long ll;
int cnt,k,head[22],vis[22];
struct node
{
    int v,next;
}e[1000];
void add(int u,int v)
{
    e[cnt].v=v; e[cnt].next=head[u];
    head[u]=cnt++;
}
void solve(int j)
{
    if(!vis[j]) vis[j]=1,k++;
    for(int i=head[j];i!=-1;i=e[i].next)
        if(!vis[e[i].v]) vis[e[i].v]=1,k++;
}
int main()
{
    int t;
    sca(t);
    while(t--)
    {
        int n,i,j,q,p,Min=100000000;
        for(i=0;i<22;i++) head[i]=-1;
        for(i=0;i<1000;i++) e[i].v=0,e[i].next=-1;
        cnt=0;
        sca(n);
        for(i=0;i<n;i++)
        {
            sca(q);
            for(j=0;j<q;j++)
                sca(p),add(i,p),add(p,i);
        }
        for(i=1;i<(1<<n);i++)
        {
            for(int ii=0;ii<22;ii++) vis[ii]=0;
            k=0;
            int sum=0;
            for(j=1;j<=n;j++)
                if(i&(1<<j)) sum++,solve(j);
            if(k==n) Min=min(sum,Min);
        }
        pri(Min);
    }
    return 0;
}



这个是用范神的二进制记录的边,好神……终于学会了,AC代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define eps 1e-7
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define MM 2000002
#define MN 305
#define INF 1000000007
using namespace std;
typedef long long ll;
int main()
{
    int t;
    sca(t);
    while(t--)
    {
        int n,i,j,q,p,Min=100000000,a[22]={0};
        sca(n);
        for(i=1;i<=n;i++)
        {
            //在二进制中从右到左第几位为1就是邻接表的边的结点一样
            a[i]|=1<<(i-1); //结点自己也要记录,如上面的邻接表vis也记录为1一样
            sca(q);
            for(j=0;j<q;j++)
                sca(p),a[i]|=1<<(p-1); //记录结点的边
        }
        for(i=1;i<(1<<n);i++)
        {
            int sum=0,ans=0;
            for(j=0;j<n;j++)
                if(i&(1<<j)) sum++,ans|=a[j+1]; //把符合的边合并二进制中的1
            //如果最后二进制中所有的位都是1的话,就是所有的结点已经覆盖了
            if(ans==(1<<n)-1) Min=min(sum,Min);
        }
        pri(Min);
    }
    return 0;
}



你可能感兴趣的:(组队赛3解题报告:精度与二进制枚举)